0

I'd like to get the coordinates of my selected Grease Pencil points and move them in relation to the 2D Camera View Plane coordinates (as you do when you use the View Transform Orientation).

View Orientation

For example, if the scene's render resolution is square and the camera view is 1080x1080, the top left corner of the Camera View Plane would be 0,0 and the bottom right corner would be 1080,1080, making this line's top point 494,118 and the bottom point 494,954 Grease Pencil Points

I found this post, Coordinates of corners of camera view border, which shows how to get the camera's view relative to the area. How could I (& should I) take a similar approach, which seems to be:

Get the camera frame in pixels

  • getting the View Frame's 4 points for the cameras frame
  • convert to world space
  • convert to pixel space with location_3d_to_region_2d

Get the Grease Pencil points in pixels:

  • convert to world space based on Grease Pencil object's matrix?
  • convert to pixel space with location_3d_to_region_2d?
  • move the points in pixels based on the Camera View coordinates?
  • convert back to the Grease Pencil's object space?

Any guidance on how to go about this would be most appreciated. Thank you!

1 Answers1

2

Well, you already sketched to steps quite right. In the code below all the points of a Grease Pencil stroke are moved following this approach:

  • Convert the point to world space, by applying layer and object transforms (location, rotation, scale).
  • Convert the world coordinates to 2D space.
  • Move the point in relation to the 2D camera view. (In this example the points are moved to the right with an offset of 30% of the view frame width.)
  • Convert these 'moved' 2D coordinates back to 3D space.
  • And convert the 'moved' 3D coordinates to the stroke's local space, by applying the inverted layer and object transforms.

So, in short, a lot of converting back and forth to get what you want!

import bpy
import mathutils
from bpy_extras.view3d_utils import location_3d_to_region_2d, region_2d_to_location_3d

Find first 3D view in active screen

From: https://blender.stackexchange.com/questions/6377/coordinates-of-corners-of-camera-view-border

def view3d_find(): for area in bpy.context.window.screen.areas: if area.type == 'VIEW_3D': v3d = area.spaces[0] rv3d = v3d.region_3d for region in area.regions: if region.type == 'WINDOW': return region, rv3d return None, None

Get 3D view region, for converting 3D coordinates to 2D

region, rv3d = view3d_find()

Get camera view frame in 2D coordinates

From: https://blender.stackexchange.com/questions/6377/coordinates-of-corners-of-camera-view-border

camera = bpy.context.scene.camera view_frame = camera.data.view_frame(scene=bpy.context.scene) view_frame = [camera.matrix_world @ v for v in view_frame] view_frame_2d = [location_3d_to_region_2d(region, rv3d, v) for v in view_frame]

Get x min and max of view frame

view_frame_min_x = view_frame_2d[2][0] view_frame_max_x = view_frame_2d[0][0]

For brevity, we assume the active object is a grease pencil object

obj = bpy.context.active_object

Get active layer

layer = obj.data.layers.active

For this example, get first stroke in layer (we assume there is one)

stroke = layer.active_frame.strokes[0]

Move all points in 2D space

for point in stroke.points: # Get world position of point, by applying # layer transform and GP object transform. # Note: the order here matters. world_co = obj.matrix_world @ layer.matrix_layer @ point.co

# Convert world coordinates to 2D space
co_2d = location_3d_to_region_2d(region, rv3d, world_co)

# As an example, move the point to the right
# with an offset of 30% of the view frame width.
delta_x = (view_frame_max_x - view_frame_min_x) * 0.30
co_2d += mathutils.Vector((delta_x, 0))

# Convert 2D coordinates back to 3D space,
# using the original world location as depth location.
# See: https://docs.blender.org/api/current/bpy_extras.view3d_utils.html#bpy_extras.view3d_utils.region_2d_to_location_3d
co_3d = region_2d_to_location_3d(region, rv3d, co_2d, world_co)

# Convert this world location to stroke local space, by applying
# the inversed transforms of GP layer and object.
# Note: the order here matters.
local_co = layer.matrix_inverse_layer @ obj.matrix_world.inverted() @ co_3d

# Assign to point
point.co = local_co

Sietse Brouwer
  • 1,265
  • 4
  • 9