From 2754ebf89b4ce7de916c2cc3cd336aef39031cc3 Mon Sep 17 00:00:00 2001 From: Pullusb Date: Mon, 31 May 2021 15:36:39 +0200 Subject: [PATCH] show main cam frame 1.3.3 - feat: show main cam frame when in draw_cam --- CHANGELOG.md | 4 + __init__.py | 2 +- handler_draw_cam.py | 253 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 230 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4684e2..01697af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +1.3.3 + +- feat: show main cam frame when in draw_cam + 1.3.2: - change: disable manip cam name drawing diff --git a/__init__.py b/__init__.py index 1f4dabb..01c0d72 100644 --- a/__init__.py +++ b/__init__.py @@ -15,7 +15,7 @@ bl_info = { "name": "GP toolbox", "description": "Set of tools for Grease Pencil in animation production", "author": "Samuel Bernou", -"version": (1, 3, 2), +"version": (1, 3, 3), "blender": (2, 91, 0), "location": "sidebar (N menu) > Gpencil > Toolbox / Gpencil properties", "warning": "", diff --git a/handler_draw_cam.py b/handler_draw_cam.py index 7aa42a2..0a1d82f 100644 --- a/handler_draw_cam.py +++ b/handler_draw_cam.py @@ -6,44 +6,47 @@ from gpu_extras.batch import batch_for_shader from bpy_extras.view3d_utils import location_3d_to_region_2d from bpy.app.handlers import persistent +from bpy.types import GizmoGroup, Gizmo + def view3d_camera_border(context, cam): - ## based on https://blender.stackexchange.com/questions/6377/coordinates-of-corners-of-camera-view-border + # based on https://blender.stackexchange.com/questions/6377/coordinates-of-corners-of-camera-view-border # cam = context.scene.camera frame = cam.data.view_frame(scene=context.scene) - # to world-space + # to world-space frame = [cam.matrix_world @ v for v in frame] # to pixelspace region, rv3d = context.region, context.space_data.region_3d frame_px = [location_3d_to_region_2d(region, rv3d, v) for v in frame] return frame_px + def draw_cam_frame_callback(self, context): if context.region_data.view_perspective != 'CAMERA': return if context.scene.camera.name != 'draw_cam': return - + main_cam = context.scene.camera.parent if not main_cam: return # if context.area != self._draw_area: # return - + # green -> (0.06, 0.4, 0.040, 0.6) # orange -> (0.45, 0.18, 0.03, 1.0) osd_color = (0.06, 0.4, 0.040, 0.4) - + frame_point = view3d_camera_border(context, main_cam) self.shader_2d = gpu.shader.from_builtin('2D_UNIFORM_COLOR') self.screen_framing = batch_for_shader( - self.shader_2d, 'LINE_LOOP', {"pos": frame_point}) + self.shader_2d, 'LINE_LOOP', {"pos": frame_point}) bgl.glLineWidth(1) self.shader_2d.bind() self.shader_2d.uniform_float("color", osd_color) self.screen_framing.draw(self.shader_2d) - + # Reset # bgl.glLineWidth(1) @@ -58,19 +61,19 @@ def draw_cam_frame_callback(self, context): # blf.draw(font_id, f'Draw cam') -## As a modal for tests +# As a modal for tests class GPTB_OT_cam_frame_draw(bpy.types.Operator): bl_idname = "gp.draw_cam_frame" bl_label = "Draw Cam Frame" bl_description = "Draw the camera frame using a modal" - bl_options = {"REGISTER"} # , "INTERNAL" + bl_options = {"REGISTER"} # , "INTERNAL" # @classmethod # def poll(cls, context): # return True def invoke(self, context, event): - ## screen color frame + # screen color frame # r = bpy.context.region # w = r.width # h = r.height @@ -78,8 +81,8 @@ class GPTB_OT_cam_frame_draw(bpy.types.Operator): # self.shader_2d = gpu.shader.from_builtin('2D_UNIFORM_COLOR') # self.screen_framing = batch_for_shader( # self.shader_2d, 'LINE_LOOP', {"pos": [(0,0), (0,h), (w,h), (w,0)]}) - - ## OpenGL handler + + # OpenGL handler self._draw_area = context.area args = (self, context) self._handle = bpy.types.SpaceView3D.draw_handler_add( @@ -87,7 +90,6 @@ class GPTB_OT_cam_frame_draw(bpy.types.Operator): context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} - def exit(self, context): bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') @@ -98,42 +100,237 @@ class GPTB_OT_cam_frame_draw(bpy.types.Operator): self.exit(context) return {"CANCELLED"} return {'PASS_THROUGH'} - # return {'RUNNING_MODAL'} -class DrawClass: - def __init__(self, context): - # print("INIT") - self._handle = bpy.types.SpaceView3D.draw_handler_add( - draw_cam_frame_callback, args, "WINDOW", "POST_PIXEL") +# GIZMO method +''' +class CameraFrameWidget(Gizmo): + bl_idname = "VIEW3D_GT_CAM" + # bl_target_properties = ( + # {"id": "offset", "type": 'FLOAT', "array_length": 1}, + # ) - def remove_handle(self): - bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') + # __slots__ = ( + # "custom_shape", + # "init_mouse_y", + # "init_value", + # ) + + # def _update_offset_matrix(self): + # # offset behind the light + # self.matrix_offset.col[3][2] = self.target_get_value("offset") / -10.0 + + def draw(self, context): + # self._update_offset_matrix() + # self.draw_custom_shape(self.custom_shape) + osd_color = (0.06, 0.4, 0.040, 0.4) + + frame_point = view3d_camera_border_3d(context, context.scene.camera.parent) + self.shader_2d = gpu.shader.from_builtin('3D_UNIFORM_COLOR') + self.screen_framing = batch_for_shader( + self.shader_2d, 'LINE_LOOP', {"pos": frame_point}) + + bgl.glLineWidth(1) + self.shader_2d.bind() + self.shader_2d.uniform_float("color", osd_color) + self.screen_framing.draw(self.shader_2d) + + # def draw_select(self, context, select_id): + # self._update_offset_matrix() + # self.draw_custom_shape(self.custom_shape, select_id=select_id) + + # def setup(self): + # if not hasattr(self, "custom_shape"): + # self.custom_shape = self.new_custom_shape('LINE_LOOP', custom_shape_verts) + + def invoke(self, context, event): + # self.init_mouse_y = event.mouse_y + # self.init_value = self.target_get_value("offset") + return {'RUNNING_MODAL'} + + def exit(self, context, cancel): + context.area.header_text_set(None) + # if cancel: + # self.target_set_value("offset", self.init_value) + + def modal(self, context, event, tweak): + # context.area.header_text_set("My Gizmo: %.4f" % value) + return {'RUNNING_MODAL'} -### --- REGISTER --- +class CameraFrameWidgetGroup(GizmoGroup): + bl_idname = "OBJECT_GGT_light_test" + bl_label = "Test Light Widget" + bl_space_type = 'VIEW_3D' + bl_region_type = 'WINDOW' + bl_options = {'3D', 'PERSISTENT'} + + @classmethod + def poll(cls, context): + # if context.region_data.view_perspective != 'CAMERA': + # return + # if context.scene.camera.name != 'draw_cam': + # return + # if not context.scene.camera.parent: + # return + # return True + return context.region_data.view_perspective == 'CAMERA' and context.scene.camera.name == 'draw_cam' and context.scene.camera.parent + + def setup(self, context): + # Assign the 'offset' target property to the light energy. + ob = context.object + gz = self.gizmos.new(CameraFrameWidget.bl_idname) + print('In setup') + # gz.target_set_prop("offset", ob.data, "energy") + + # gz.color = 1.0, 0.5, 1.0 + # gz.alpha = 0.5 + + # gz.color_highlight = 1.0, 1.0, 1.0 + # gz.alpha_highlight = 0.5 + + # units are large, so shrink to something more reasonable. + # gz.scale_basis = 0.1 + gz.use_draw_modal = True + + + def refresh(self, context): + ob = context.object0 + # gz = self.energy_gizmo + # gz.matrix_basis = ob.matrix_world.normalized() + +''' +# USED 0CODE + + +def extrapolate_points_by_length(a, b, length): + ''' + Return a third point C from by continuing in AB direction + Length define BC distance. both vector2 and vector3 + ''' + # return b + ((b - a).normalized() * length)# one shot + ab = b - a + if not ab: + return None + return b + (ab.normalized() * length) + + +def view3d_camera_border_3d(context, cam): + '''Return frame border as 3D coordinate''' + frame = cam.data.view_frame(scene=context.scene) + frame = [cam.matrix_world @ v for v in frame] + return frame + + +class CameraFrameWidget(Gizmo): + bl_idname = "VIEW3D_GT_CAM" + + def draw(self, context): + # 3D0 draw + osd_color = (0.06, 0.4, 0.040, 0.4) + + frame_point = view3d_camera_border_3d( + context, context.scene.camera.parent) + self.shader_2d = gpu.shader.from_builtin('3D_UNIFORM_COLOR') + + self.screen_framing = batch_for_shader( + self.shader_2d, 'LINE_LOOP', {"pos": frame_point}) + + bgl.glLineWidth(1) + self.shader_2d.bind() + self.shader_2d.uniform_float("color", osd_color) + self.screen_framing.draw(self.shader_2d) + + # WIP -> custom passepartout + + + ## frame positions + # D-----A + # | | + # C-----B + + # a = frame_point[0] + # b = frame_point[1] + # c = frame_point[2] + # d = frame_point[3] + + # ext = 0.2 + # rup = extrapolate_points_by_length(a,b, ext) + # rdn = extrapolate_points_by_length(b,a, ext) + + # rupext = rup + ((a-c).normalized() * ext) + # rdnext = rdn + ((a-c).normalized() * ext) + + + # rect = [rup, rdn, rupext, rdnext] + + # ### passpartout_points = [] + # self.passepartout = batch_for_shader( + # self.shader_2d, 'TRI_FAN', {"pos": rect}) # TRIS + + # self.shader_2d.bind() + # self.shader_2d.uniform_float("color", osd_color) + # self.passepartout.draw(self.shader_2d) + + # def invoke(self, context, event): + # return {'RUNNING_MODAL'} + + # def exit(self, context, cancel): + # # context.area.header_text_set(None) + # return + + # def modal(self, context, event, tweak): + # return {'RUNNING_MODAL'} + + +class CameraFrameWidgetGroup(GizmoGroup): + bl_idname = "OBJECT_GGT_light_test" + bl_label = "Test Light Widget" + bl_space_type = 'VIEW_3D' + bl_region_type = 'WINDOW' + bl_options = {'3D', 'PERSISTENT'} + + @classmethod + def poll(cls, context): + return context.region_data.view_perspective == 'CAMERA' and context.scene.camera.name == 'draw_cam' and context.scene.camera.parent + + def setup(self, context): + gz = self.gizmos.new(CameraFrameWidget.bl_idname) + + +# --- REGISTER --- + + +classes = ( + # GPTB_OT_cam_frame_draw, + CameraFrameWidget, + CameraFrameWidgetGroup, +) + def register(): if not bpy.app.background: - bpy.utils.register_class(GPTB_OT_cam_frame_draw) - + for cls in classes: + bpy.utils.register_class(cls) + # ha = DrawClass() # _handle = bpy.types.SpaceView3D.draw_handler_add( # draw_cam_frame_callback, args, "WINDOW", "POST_PIXEL") + def unregister(): if not bpy.app.background: - bpy.utils.unregister_class(GPTB_OT_cam_frame_draw) - + for cls in classes: + bpy.utils.unregister_class(cls) + # ha.remove_handle() # bpy.types.SpaceView3D.draw_handler_remove(_handle, 'WINDOW') - # if 'draw_cam_frame_callback' in [hand.__name__ for hand in bpy.app.handlers.save_pre]: # bpy.app.handlers.save_pre.remove(remap_relative) if __name__ == "__main__": - register() \ No newline at end of file + register()