GPencil Tools: Canvas rotate improvement

In camera view : New rotate canvas pivot mode from view center instead of camera center (enabled by default).
Fix rotate canvas precision in free navigation.
Also now compatible with region overlap toggled off.
This commit is contained in:
Samuel Bernou 2021-07-06 23:56:52 +02:00
parent 046114b96a
commit 81b348c452
3 changed files with 66 additions and 5 deletions

View File

@ -21,7 +21,7 @@ bl_info = {
"name": "Grease Pencil Tools",
"description": "Extra tools for Grease Pencil",
"author": "Samuel Bernou, Antonio Vazquez, Daniel Martinez Lara, Matias Mendiola",
"version": (1, 4, 3),
"version": (1, 5, 0),
"blender": (2, 91, 0),
"location": "Sidebar > Grease Pencil > Grease Pencil Tools",
"warning": "",

View File

@ -89,6 +89,11 @@ class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
name = "Use Hud",
description = "Display angle lines and angle value as text on viewport",
default = False)
canvas_use_view_center: BoolProperty(
name = "Rotate From View Center In Camera",
description = "Rotate from view center in camera view, Else rotate from camera center",
default = True)
## Canvas rotate
canvas_use_shortcut: BoolProperty(
@ -197,6 +202,7 @@ class GreasePencilAddonPrefs(bpy.types.AddonPreferences):
else:
box.label(text="No hotkey has been set automatically. Following operators needs to be set manually:", icon="ERROR")
box.label(text="view3d.rotate_canvas")
box.prop(self, 'canvas_use_view_center')
box.prop(self, 'canvas_use_hud')
## SCRUB TIMELINE

View File

@ -43,6 +43,15 @@ def draw_callback_px(self, context):
shader.uniform_float("color", (0.3, 0.7, 0.2, 0.5))
batch.draw(shader)
## debug lines
# batch = batch_for_shader(shader, 'LINES', {"pos": [
# (0,0), (context.area.width, context.area.height),
# (context.area.width, 0), (0, context.area.height)
# ]})
# shader.bind()
# shader.uniform_float("color", (0.8, 0.1, 0.1, 0.5))
# batch.draw(shader)
# restore opengl defaults
bgl.glLineWidth(1)
bgl.glDisable(bgl.GL_BLEND)
@ -111,7 +120,26 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
self.cam.matrix_world = self.cam_matrix
self.cam.rotation_euler.rotate_axis("Z", self.angle)
else:#free view
if self.use_view_center:
## apply inverse of the rotation on view offset in cam rotate from view center
neg = -self.angle
rot_mat2d = mathutils.Matrix([[math.cos(neg), -math.sin(neg)], [math.sin(neg), math.cos(neg)]])
# scale_mat = mathutils.Matrix([[1.0, 0.0], [0.0, self.ratio]])
new_cam_offset = self.view_cam_offset.copy()
## area deformation correction
new_cam_offset = mathutils.Vector((new_cam_offset[0], new_cam_offset[1] * self.ratio))
## rotate by matrix
new_cam_offset.rotate(rot_mat2d)
## area deformation restore
new_cam_offset = mathutils.Vector((new_cam_offset[0], new_cam_offset[1] * self.ratio_inv))
context.space_data.region_3d.view_camera_offset = new_cam_offset
else: # free view
context.space_data.region_3d.view_rotation = self._rotation
rot = context.space_data.region_3d.view_rotation
rot = rot.to_euler()
@ -139,20 +167,38 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
self.execute(context)
if self.in_cam:
self.cam.matrix_world = self.cam_matrix
context.space_data.region_3d.view_camera_offset = self.view_cam_offset
else:
context.space_data.region_3d.view_rotation = self._rotation
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
self.current_area = context.area
prefs = get_addon_prefs()
self.hud = prefs.canvas_use_hud
self.use_view_center = prefs.canvas_use_view_center
self.angle = 0.0
self.in_cam = context.region_data.view_perspective == 'CAMERA'
## store ratio for view rotate correction
# CORRECT UI OVERLAP FROM HEADER TOOLBAR
regs = context.area.regions
if context.preferences.system.use_region_overlap:
w = context.area.width
# minus tool header
h = context.area.height - regs[0].height
else:
# minus tool leftbar + sidebar right
w = context.area.width - regs[2].width - regs[3].width
# minus tool header + header
h = context.area.height - regs[0].height - regs[1].height
self.ratio = h / w
self.ratio_inv = w / h
if self.in_cam:
# Get camera from scene
self.cam = bpy.context.scene.camera
@ -161,8 +207,12 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
if self.cam.lock_rotation[:] != (False, False, False):
self.report({'WARNING'}, 'Camera rotation is locked')
return {'CANCELLED'}
if self.use_view_center:
self.center = mathutils.Vector((w/2, h/2))
else:
self.center = self.get_center_view(context, self.cam)
self.center = self.get_center_view(context, self.cam)
# store original rotation mode
self.org_rotation_mode = self.cam.rotation_mode
# set to euler to works with quaternions, restored at finish
@ -170,9 +220,13 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
# store camera matrix world
self.cam_matrix = self.cam.matrix_world.copy()
# self.cam_init_euler = self.cam.rotation_euler.copy()
## initialize current view_offset in camera
self.view_cam_offset = mathutils.Vector(context.space_data.region_3d.view_camera_offset)
else:
self.center = mathutils.Vector((context.area.width/2, context.area.height/2))
self.center = mathutils.Vector((w/2, h/2))
# self.center = mathutils.Vector((context.area.width/2, context.area.height/2))
# store current rotation
self._rotation = context.space_data.region_3d.view_rotation.copy()
@ -188,6 +242,7 @@ class RC_OT_RotateCanvas(bpy.types.Operator):
# Initializes the current vector with the same initial vector.
self.vector_current = self.vector_initial.copy()
#Snap keys
self.snap_ctrl = not prefs.use_ctrl
self.snap_shift = not prefs.use_shift