gp_toolbox/handler_draw_cam.py

184 lines
5.5 KiB
Python

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()