This repository was archived by the owner on Aug 11, 2025. It is now read-only.
forked from ChristopheSeux/CameraField
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathoperators.py
More file actions
156 lines (118 loc) · 5.87 KB
/
operators.py
File metadata and controls
156 lines (118 loc) · 5.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import bpy
import random
from math import sqrt
from mathutils import Vector
from time import time
from .functions import draw_callback_3d
global_cameras = []
class CAMERA_OT_bake_field_to_object(bpy.types.Operator):
bl_idname = "camerafield.bake_to_object"
bl_label = "Bake Camera Frustum To Object"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(self, context):
return global_cameras
def execute(self, context):
bake_data = bpy.data.meshes.new('CameraField')
bake_object = bpy.data.objects.new('CameraField', bake_data)
if not bake_object.name in context.scene.collection.all_objects:
context.collection.objects.link(bake_object)
verts = []
for cam in global_cameras:
if cam['camera_data'].camera_frustum_settings.enable:
for co in cam["co"]:
verts.append(co)
bake_data.from_pydata(verts, [], [])
return {'FINISHED'}
class CAMERA_OT_view_camera_field(bpy.types.Operator):
bl_idname = "camerafield.view_field"
bl_label = "Add Camera Frustum"
bl_options = {'REGISTER', 'UNDO'}
bl_description = "Press escape to quit"
def modal(self, context, event):
try:
context.area.tag_redraw()
except AttributeError:
bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW')
global_cameras.clear()
return {'CANCELLED'}
if event.type in {'ESC'}:
bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, 'WINDOW')
global_cameras.clear()
return {'CANCELLED'}
return {'PASS_THROUGH'}
def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
scene = context.scene
self.current_frame = scene.frame_current
if global_cameras:
op_running = True
else:
op_running = False
if scene.camera_frustum_settings.only_active:
cams = (scene.camera,)
else:
cams = [o for o in context.visible_objects if o.type == 'CAMERA']
ratio = context.scene.render.resolution_y / context.scene.render.resolution_x
seed = time() # Different seed at each execution
random.seed(seed) # Use a predictable seed
for cam in cams:
cam_color = cam.data.camera_frustum_settings.color
camera_points = {"color": cam_color,
"co": [],
"camera_data": cam.data}
for i in range(scene.frame_start, scene.frame_end + 1):
scene.frame_set(i)
if scene.camera_frustum_settings.distribution == 'TRAIL':
# Use the same seed at each frame, so each ray ends up
# at the same point in camera space, leaving a trail
random.seed(seed)
if not cam.data.camera_frustum_settings.enable:
continue
if cam.data.type not in ('PERSP', 'ORTHO'):
self.report({'WARNING'}, "Camera type unsupported: " + cam.name)
continue
cam_coord = cam.matrix_world.to_translation()
cam_direction = Vector(cam.matrix_world.transposed()[2][:-1])
frame = cam.data.view_frame(scene=scene)
density = scene.camera_frustum_settings.density
frame = [cam.matrix_world.normalized() @ corner for corner in frame]
vector_x = frame[0] - frame[3]
vector_y = frame[2] - frame[3]
if scene.camera_frustum_settings.distribution in {'RANDOM', 'TRAIL'}:
points = [(random.random(), random.random())
for z in range(density)
]
elif scene.camera_frustum_settings.distribution == 'GRID':
density_x = sqrt(density) / sqrt(ratio)
density_y = sqrt(density) * sqrt(ratio)
points = [(x / (int(density_x) - 1),
y / (int(density_y) - 1)
)
for x in range(int(density_x))
for y in range(int(density_y))
]
for x, y in points:
point = (frame[3] + vector_x * x + vector_y * y)
if cam.data.type == 'PERSP':
ray = scene.ray_cast(context.view_layer.depsgraph, cam_coord, point - cam_coord)
elif cam.data.type == 'ORTHO':
ray = scene.ray_cast(context.view_layer.depsgraph, point, -cam_direction)
if ray[0]:
ray_closer = ray[1] + (point-ray[1]).normalized() * 0.02
if not ray_closer in camera_points["co"]:
camera_points["co"].append(ray_closer)
global_cameras.append(camera_points)
if op_running:
return {'FINISHED'}
else:
# the arguments we pass the callback
args = (global_cameras,)
# Add the region OpenGL drawing callback
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(draw_callback_3d, args, 'WINDOW', 'POST_VIEW')
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "View3D not found, cannot run operator")
return {'CANCELLED'}