import bpy import gpu # import blf 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 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_2d(context, cam): # 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 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 vertices_to_line_loop(v_list, closed=True) -> list: '''Take a sequence of vertices return a position lists of segments to create a line loop passing in all points the result is usable with gpu_shader 'LINES' ex: vlist = [a,b,c] -> closed=True return [a,b,b,c,c,a], closed=False return [a,b,b,c] ''' loop = [] for i in range(len(v_list) - 1): loop += [v_list[i], v_list[i + 1]] if closed: # Add segment between last and first to close loop loop += [v_list[-1], v_list[0]] return loop def draw_cam_frame_callback_2d(): context = bpy.context if context.region_data.view_perspective != 'CAMERA': return if not context.scene.camera or context.scene.camera.name != 'draw_cam': return main_cam = context.scene.camera.parent if not main_cam: return gpu.state.blend_set('ALPHA') frame_point = view3d_camera_border_2d( context, context.scene.camera.parent) shader_2d = gpu.shader.from_builtin('UNIFORM_COLOR') # POLYLINE_FLAT_COLOR # gpu.shader.from_builtin('2D_UNIFORM_COLOR') if context.scene.gptoolprops.drawcam_passepartout: ### PASSEPARTOUT # frame positions # # lupext lup rup rupext # D-----A # | | # C-----B # ldnext ldn rdn lnext a = frame_point[0] b = frame_point[1] c = frame_point[2] d = frame_point[3] ext = 10000 rup = extrapolate_points_by_length(b,a, ext) rdn = extrapolate_points_by_length(a,b, ext) rupext = rup + ((a-d).normalized() * ext) rdnext = rdn + ((a-d).normalized() * ext) lup = extrapolate_points_by_length(c,d, ext) ldn = extrapolate_points_by_length(d,c, ext) lupext = lup + ((c-b).normalized() * ext) ldnext = ldn + ((c-b).normalized() * ext) # ppp_color = (1.0, 1.0, 0.0, 1) ppp_color = (0.0, 0.0, 0.0, context.scene.camera.data.passepartout_alpha) rect = [rup, rdn, rupext, rdnext, lup, ldn, lupext, ldnext, a, b, c, d] ## convert to 2d # region, rv3d = context.region, context.space_data.region_3d # rect = [location_3d_to_region_2d(region, rv3d, v) for v in rect] # lupext=6 lup=4 rup=0 rupext=2 # d=11, a=8 # c=10, b=9 # ldnext=7 ldn=5 rdn=1 dnpext=3 indices = [(0,1,2), (1,2,3), (4,5,6), (5,6,7), (8,11,4), (8,4,0), (10,9,5), (9,5,1), ] # ### passpartout_points passepartout = batch_for_shader( shader_2d, 'TRIS', {"pos": rect}, indices=indices) # shader_2d, 'LINE_LOOP', {"pos": rect}) shader_2d.bind() shader_2d.uniform_float("color", ppp_color) passepartout.draw(shader_2d) ### Camera framing trace over gpu.state.line_width_set(1.0) # bgl.glEnable(bgl.GL_LINE_SMOOTH) # old smooth """ ## need to accurately detect viewport background color (difficult) ### COUNTER CURRENT FRAMING if False: camf = view3d_camera_border_2d( context, context.scene.camera) ca = (camf[0].x + 1, camf[0].y + 1) cb = (camf[1].x + 1, camf[1].y - 1) cc = (camf[2].x - 1, camf[2].y - 1) cd = (camf[3].x - 1, camf[3].y + 1) screen_framing = batch_for_shader( shader_2d, 'LINE_LOOP', {"pos": [ca, cb, cc, cd]}) shader_2d.bind() shader_2d.uniform_float("color", (0.25, 0.25, 0.25, 1.0)) # shader_2d.uniform_float("color", (0.9, 0.9, 0.9, 1.0)) screen_framing.draw(shader_2d) """ ### FRAMING # frame_color = (0.06, 0.4, 0.040, 0.5) frame_color = (0.0, 0.0, 0.25, 1.0) screen_framing = batch_for_shader( shader_2d, 'LINES', {"pos": vertices_to_line_loop(frame_point)}) shader_2d.bind() shader_2d.uniform_float("color", frame_color) screen_framing.draw(shader_2d) # bgl.glDisable(bgl.GL_LINE_SMOOTH) # old smooth gpu.state.blend_set('NONE') draw_handle = None def register(): if bpy.app.background: return global draw_handle draw_handle = bpy.types.SpaceView3D.draw_handler_add( draw_cam_frame_callback_2d, (), "WINDOW", "POST_PIXEL") def unregister(): if bpy.app.background: return global draw_handle if draw_handle: bpy.types.SpaceView3D.draw_handler_remove(draw_handle, 'WINDOW') if __name__ == "__main__": register()