Fix T98039: Node Wrangler node preview no longer working
[blender-addons.git] / viewport_vr_preview / operators.py
blob67638ea474fc2f4792b2070644439239cb44c4a6
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # <pep8 compliant>
5 if "bpy" in locals():
6 import importlib
7 importlib.reload(properties)
8 else:
9 from . import properties
11 import bpy
12 from bpy.types import (
13 Gizmo,
14 GizmoGroup,
15 Operator,
17 import bgl
18 import math
19 from math import radians
20 from mathutils import Euler, Matrix, Quaternion, Vector
23 ### Landmarks.
24 class VIEW3D_OT_vr_landmark_add(Operator):
25 bl_idname = "view3d.vr_landmark_add"
26 bl_label = "Add VR Landmark"
27 bl_description = "Add a new VR landmark to the list and select it"
28 bl_options = {'UNDO', 'REGISTER'}
30 def execute(self, context):
31 scene = context.scene
32 landmarks = scene.vr_landmarks
34 landmarks.add()
36 # select newly created set
37 scene.vr_landmarks_selected = len(landmarks) - 1
39 return {'FINISHED'}
42 class VIEW3D_OT_vr_landmark_from_camera(Operator):
43 bl_idname = "view3d.vr_landmark_from_camera"
44 bl_label = "Add VR Landmark from Camera"
45 bl_description = "Add a new VR landmark from the active camera object to the list and select it"
46 bl_options = {'UNDO', 'REGISTER'}
48 @classmethod
49 def poll(cls, context):
50 cam_selected = False
52 vl_objects = bpy.context.view_layer.objects
53 if vl_objects.active and vl_objects.active.type == 'CAMERA':
54 cam_selected = True
55 return cam_selected
57 def execute(self, context):
58 scene = context.scene
59 landmarks = scene.vr_landmarks
60 cam = context.view_layer.objects.active
61 lm = landmarks.add()
62 lm.type = 'OBJECT'
63 lm.base_pose_object = cam
64 lm.name = "LM_" + cam.name
66 # select newly created set
67 scene.vr_landmarks_selected = len(landmarks) - 1
69 return {'FINISHED'}
72 class VIEW3D_OT_vr_landmark_from_session(Operator):
73 bl_idname = "view3d.vr_landmark_from_session"
74 bl_label = "Add VR Landmark from Session"
75 bl_description = "Add VR landmark from the viewer pose of the running VR session to the list and select it"
76 bl_options = {'UNDO', 'REGISTER'}
78 @classmethod
79 def poll(cls, context):
80 return bpy.types.XrSessionState.is_running(context)
82 def execute(self, context):
83 scene = context.scene
84 landmarks = scene.vr_landmarks
85 wm = context.window_manager
87 lm = landmarks.add()
88 lm.type = "CUSTOM"
89 scene.vr_landmarks_selected = len(landmarks) - 1
91 loc = wm.xr_session_state.viewer_pose_location
92 rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
94 lm.base_pose_location = loc
95 lm.base_pose_angle = rot[2]
97 return {'FINISHED'}
100 class VIEW3D_OT_vr_camera_landmark_from_session(Operator):
101 bl_idname = "view3d.vr_camera_landmark_from_session"
102 bl_label = "Add Camera and VR Landmark from Session"
103 bl_description = "Create a new Camera and VR Landmark from the viewer pose of the running VR session and select it"
104 bl_options = {'UNDO', 'REGISTER'}
106 @classmethod
107 def poll(cls, context):
108 return bpy.types.XrSessionState.is_running(context)
110 def execute(self, context):
111 scene = context.scene
112 landmarks = scene.vr_landmarks
113 wm = context.window_manager
115 lm = landmarks.add()
116 lm.type = 'OBJECT'
117 scene.vr_landmarks_selected = len(landmarks) - 1
119 loc = wm.xr_session_state.viewer_pose_location
120 rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
122 cam = bpy.data.cameras.new("Camera_" + lm.name)
123 new_cam = bpy.data.objects.new("Camera_" + lm.name, cam)
124 scene.collection.objects.link(new_cam)
125 new_cam.location = loc
126 new_cam.rotation_euler = rot
128 lm.base_pose_object = new_cam
130 return {'FINISHED'}
133 class VIEW3D_OT_update_vr_landmark(Operator):
134 bl_idname = "view3d.update_vr_landmark"
135 bl_label = "Update Custom VR Landmark"
136 bl_description = "Update the selected landmark from the current viewer pose in the VR session"
137 bl_options = {'UNDO', 'REGISTER'}
139 @classmethod
140 def poll(cls, context):
141 selected_landmark = properties.VRLandmark.get_selected_landmark(context)
142 return bpy.types.XrSessionState.is_running(context) and selected_landmark.type == 'CUSTOM'
144 def execute(self, context):
145 wm = context.window_manager
147 lm = properties.VRLandmark.get_selected_landmark(context)
149 loc = wm.xr_session_state.viewer_pose_location
150 rot = wm.xr_session_state.viewer_pose_rotation.to_euler()
152 lm.base_pose_location = loc
153 lm.base_pose_angle = rot
155 # Re-activate the landmark to trigger viewer reset and flush landmark settings to the session settings.
156 properties.vr_landmark_active_update(None, context)
158 return {'FINISHED'}
161 class VIEW3D_OT_vr_landmark_remove(Operator):
162 bl_idname = "view3d.vr_landmark_remove"
163 bl_label = "Remove VR Landmark"
164 bl_description = "Delete the selected VR landmark from the list"
165 bl_options = {'UNDO', 'REGISTER'}
167 def execute(self, context):
168 scene = context.scene
169 landmarks = scene.vr_landmarks
171 if len(landmarks) > 1:
172 landmark_selected_idx = scene.vr_landmarks_selected
173 landmarks.remove(landmark_selected_idx)
175 scene.vr_landmarks_selected -= 1
177 return {'FINISHED'}
180 class VIEW3D_OT_cursor_to_vr_landmark(Operator):
181 bl_idname = "view3d.cursor_to_vr_landmark"
182 bl_label = "Cursor to VR Landmark"
183 bl_description = "Move the 3D Cursor to the selected VR Landmark"
184 bl_options = {'UNDO', 'REGISTER'}
186 @classmethod
187 def poll(cls, context):
188 lm = properties.VRLandmark.get_selected_landmark(context)
189 if lm.type == 'SCENE_CAMERA':
190 return context.scene.camera is not None
191 elif lm.type == 'OBJECT':
192 return lm.base_pose_object is not None
194 return True
196 def execute(self, context):
197 scene = context.scene
198 lm = properties.VRLandmark.get_selected_landmark(context)
199 if lm.type == 'SCENE_CAMERA':
200 lm_pos = scene.camera.location
201 elif lm.type == 'OBJECT':
202 lm_pos = lm.base_pose_object.location
203 else:
204 lm_pos = lm.base_pose_location
205 scene.cursor.location = lm_pos
207 return{'FINISHED'}
210 class VIEW3D_OT_add_camera_from_vr_landmark(Operator):
211 bl_idname = "view3d.add_camera_from_vr_landmark"
212 bl_label = "New Camera from VR Landmark"
213 bl_description = "Create a new Camera from the selected VR Landmark"
214 bl_options = {'UNDO', 'REGISTER'}
216 def execute(self, context):
217 scene = context.scene
218 lm = properties.VRLandmark.get_selected_landmark(context)
220 cam = bpy.data.cameras.new("Camera_" + lm.name)
221 new_cam = bpy.data.objects.new("Camera_" + lm.name, cam)
222 scene.collection.objects.link(new_cam)
223 angle = lm.base_pose_angle
224 new_cam.location = lm.base_pose_location
225 new_cam.rotation_euler = (math.pi / 2, 0, angle)
227 return {'FINISHED'}
230 class VIEW3D_OT_camera_to_vr_landmark(Operator):
231 bl_idname = "view3d.camera_to_vr_landmark"
232 bl_label = "Scene Camera to VR Landmark"
233 bl_description = "Position the scene camera at the selected landmark"
234 bl_options = {'UNDO', 'REGISTER'}
236 @classmethod
237 def poll(cls, context):
238 return context.scene.camera is not None
240 def execute(self, context):
241 scene = context.scene
242 lm = properties.VRLandmark.get_selected_landmark(context)
244 cam = scene.camera
245 angle = lm.base_pose_angle
246 cam.location = lm.base_pose_location
247 cam.rotation_euler = (math.pi / 2, 0, angle)
249 return {'FINISHED'}
252 class VIEW3D_OT_vr_landmark_activate(Operator):
253 bl_idname = "view3d.vr_landmark_activate"
254 bl_label = "Activate VR Landmark"
255 bl_description = "Change to the selected VR landmark from the list"
256 bl_options = {'UNDO', 'REGISTER'}
258 index: bpy.props.IntProperty(
259 name="Index",
260 options={'HIDDEN'},
263 def execute(self, context):
264 scene = context.scene
266 if self.index >= len(scene.vr_landmarks):
267 return {'CANCELLED'}
269 scene.vr_landmarks_active = (
270 self.index if self.properties.is_property_set(
271 "index") else scene.vr_landmarks_selected
274 return {'FINISHED'}
277 ### Gizmos.
278 class VIEW3D_GT_vr_camera_cone(Gizmo):
279 bl_idname = "VIEW_3D_GT_vr_camera_cone"
281 aspect = 1.0, 1.0
283 def draw(self, context):
284 if not hasattr(self, "frame_shape"):
285 aspect = self.aspect
287 frame_shape_verts = (
288 (-aspect[0], -aspect[1], -1.0),
289 (aspect[0], -aspect[1], -1.0),
290 (aspect[0], aspect[1], -1.0),
291 (-aspect[0], aspect[1], -1.0),
293 lines_shape_verts = (
294 (0.0, 0.0, 0.0),
295 frame_shape_verts[0],
296 (0.0, 0.0, 0.0),
297 frame_shape_verts[1],
298 (0.0, 0.0, 0.0),
299 frame_shape_verts[2],
300 (0.0, 0.0, 0.0),
301 frame_shape_verts[3],
304 self.frame_shape = self.new_custom_shape(
305 'LINE_LOOP', frame_shape_verts)
306 self.lines_shape = self.new_custom_shape(
307 'LINES', lines_shape_verts)
309 # Ensure correct GL state (otherwise other gizmos might mess that up)
310 bgl.glLineWidth(1)
311 bgl.glEnable(bgl.GL_BLEND)
313 self.draw_custom_shape(self.frame_shape)
314 self.draw_custom_shape(self.lines_shape)
317 class VIEW3D_GT_vr_controller_grip(Gizmo):
318 bl_idname = "VIEW_3D_GT_vr_controller_grip"
320 def draw(self, context):
321 bgl.glLineWidth(1)
322 bgl.glEnable(bgl.GL_BLEND)
324 self.color = 0.422, 0.438, 0.446
325 self.draw_preset_circle(self.matrix_basis, axis='POS_X')
326 self.draw_preset_circle(self.matrix_basis, axis='POS_Y')
327 self.draw_preset_circle(self.matrix_basis, axis='POS_Z')
330 class VIEW3D_GT_vr_controller_aim(Gizmo):
331 bl_idname = "VIEW_3D_GT_vr_controller_aim"
333 def draw(self, context):
334 bgl.glLineWidth(1)
335 bgl.glEnable(bgl.GL_BLEND)
337 self.color = 1.0, 0.2, 0.322
338 self.draw_preset_arrow(self.matrix_basis, axis='POS_X')
339 self.color = 0.545, 0.863, 0.0
340 self.draw_preset_arrow(self.matrix_basis, axis='POS_Y')
341 self.color = 0.157, 0.565, 1.0
342 self.draw_preset_arrow(self.matrix_basis, axis='POS_Z')
345 class VIEW3D_GGT_vr_viewer_pose(GizmoGroup):
346 bl_idname = "VIEW3D_GGT_vr_viewer_pose"
347 bl_label = "VR Viewer Pose Indicator"
348 bl_space_type = 'VIEW_3D'
349 bl_region_type = 'WINDOW'
350 bl_options = {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
352 @classmethod
353 def poll(cls, context):
354 view3d = context.space_data
355 return (
356 view3d.shading.vr_show_virtual_camera and
357 bpy.types.XrSessionState.is_running(context) and
358 not view3d.mirror_xr_session
361 @staticmethod
362 def _get_viewer_pose_matrix(context):
363 wm = context.window_manager
365 loc = wm.xr_session_state.viewer_pose_location
366 rot = wm.xr_session_state.viewer_pose_rotation
368 rotmat = Matrix.Identity(3)
369 rotmat.rotate(rot)
370 rotmat.resize_4x4()
371 transmat = Matrix.Translation(loc)
373 return transmat @ rotmat
375 def setup(self, context):
376 gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
377 gizmo.aspect = 1 / 3, 1 / 4
379 gizmo.color = gizmo.color_highlight = 0.2, 0.6, 1.0
380 gizmo.alpha = 1.0
382 self.gizmo = gizmo
384 def draw_prepare(self, context):
385 self.gizmo.matrix_basis = self._get_viewer_pose_matrix(context)
388 class VIEW3D_GGT_vr_controller_poses(GizmoGroup):
389 bl_idname = "VIEW3D_GGT_vr_controller_poses"
390 bl_label = "VR Controller Poses Indicator"
391 bl_space_type = 'VIEW_3D'
392 bl_region_type = 'WINDOW'
393 bl_options = {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
395 @classmethod
396 def poll(cls, context):
397 view3d = context.space_data
398 return (
399 view3d.shading.vr_show_controllers and
400 bpy.types.XrSessionState.is_running(context) and
401 not view3d.mirror_xr_session
404 @staticmethod
405 def _get_controller_pose_matrix(context, idx, is_grip, scale):
406 wm = context.window_manager
408 loc = None
409 rot = None
410 if is_grip:
411 loc = wm.xr_session_state.controller_grip_location_get(context, idx)
412 rot = wm.xr_session_state.controller_grip_rotation_get(context, idx)
413 else:
414 loc = wm.xr_session_state.controller_aim_location_get(context, idx)
415 rot = wm.xr_session_state.controller_aim_rotation_get(context, idx)
417 rotmat = Matrix.Identity(3)
418 rotmat.rotate(Quaternion(Vector(rot)))
419 rotmat.resize_4x4()
420 transmat = Matrix.Translation(loc)
421 scalemat = Matrix.Scale(scale, 4)
423 return transmat @ rotmat @ scalemat
425 def setup(self, context):
426 for idx in range(2):
427 self.gizmos.new(VIEW3D_GT_vr_controller_grip.bl_idname)
428 self.gizmos.new(VIEW3D_GT_vr_controller_aim.bl_idname)
430 for gizmo in self.gizmos:
431 gizmo.aspect = 1 / 3, 1 / 4
432 gizmo.color_highlight = 1.0, 1.0, 1.0
433 gizmo.alpha = 1.0
435 def draw_prepare(self, context):
436 grip_idx = 0
437 aim_idx = 0
438 idx = 0
439 scale = 1.0
440 for gizmo in self.gizmos:
441 is_grip = (gizmo.bl_idname == VIEW3D_GT_vr_controller_grip.bl_idname)
442 if (is_grip):
443 idx = grip_idx
444 grip_idx += 1
445 scale = 0.1
446 else:
447 idx = aim_idx
448 aim_idx += 1
449 scale = 0.5
450 gizmo.matrix_basis = self._get_controller_pose_matrix(context, idx, is_grip, scale)
453 class VIEW3D_GGT_vr_landmarks(GizmoGroup):
454 bl_idname = "VIEW3D_GGT_vr_landmarks"
455 bl_label = "VR Landmark Indicators"
456 bl_space_type = 'VIEW_3D'
457 bl_region_type = 'WINDOW'
458 bl_options = {'3D', 'PERSISTENT', 'SCALE'}
460 @classmethod
461 def poll(cls, context):
462 view3d = context.space_data
463 return (
464 view3d.shading.vr_show_landmarks
467 def setup(self, context):
468 pass
470 def draw_prepare(self, context):
471 # first delete the old gizmos
472 for g in self.gizmos:
473 self.gizmos.remove(g)
475 scene = context.scene
476 landmarks = scene.vr_landmarks
478 for lm in landmarks:
479 if ((lm.type == 'SCENE_CAMERA' and not scene.camera) or
480 (lm.type == 'OBJECT' and not lm.base_pose_object)):
481 continue
483 gizmo = self.gizmos.new(VIEW3D_GT_vr_camera_cone.bl_idname)
484 gizmo.aspect = 1 / 3, 1 / 4
486 gizmo.color = gizmo.color_highlight = 0.2, 1.0, 0.6
487 gizmo.alpha = 1.0
489 self.gizmo = gizmo
491 if lm.type == 'SCENE_CAMERA':
492 cam = scene.camera
493 lm_mat = cam.matrix_world if cam else Matrix.Identity(4)
494 elif lm.type == 'OBJECT':
495 lm_mat = lm.base_pose_object.matrix_world
496 else:
497 angle = lm.base_pose_angle
498 raw_rot = Euler((radians(90.0), 0, angle))
500 rotmat = Matrix.Identity(3)
501 rotmat.rotate(raw_rot)
502 rotmat.resize_4x4()
504 transmat = Matrix.Translation(lm.base_pose_location)
506 lm_mat = transmat @ rotmat
508 self.gizmo.matrix_basis = lm_mat
511 classes = (
512 VIEW3D_OT_vr_landmark_add,
513 VIEW3D_OT_vr_landmark_remove,
514 VIEW3D_OT_vr_landmark_activate,
515 VIEW3D_OT_vr_landmark_from_session,
516 VIEW3D_OT_vr_camera_landmark_from_session,
517 VIEW3D_OT_add_camera_from_vr_landmark,
518 VIEW3D_OT_camera_to_vr_landmark,
519 VIEW3D_OT_vr_landmark_from_camera,
520 VIEW3D_OT_cursor_to_vr_landmark,
521 VIEW3D_OT_update_vr_landmark,
523 VIEW3D_GT_vr_camera_cone,
524 VIEW3D_GT_vr_controller_grip,
525 VIEW3D_GT_vr_controller_aim,
526 VIEW3D_GGT_vr_viewer_pose,
527 VIEW3D_GGT_vr_controller_poses,
528 VIEW3D_GGT_vr_landmarks,
532 def register():
533 for cls in classes:
534 bpy.utils.register_class(cls)
537 def unregister():
538 for cls in classes:
539 bpy.utils.unregister_class(cls)