1 # SPDX-License-Identifier: GPL-2.0-or-later
7 importlib
.reload(properties
)
9 from . import properties
12 from bpy
.types
import (
19 from math
import radians
20 from mathutils
import Euler
, Matrix
, Quaternion
, Vector
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
):
32 landmarks
= scene
.vr_landmarks
36 # select newly created set
37 scene
.vr_landmarks_selected
= len(landmarks
) - 1
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'}
49 def poll(cls
, context
):
52 vl_objects
= bpy
.context
.view_layer
.objects
53 if vl_objects
.active
and vl_objects
.active
.type == 'CAMERA':
57 def execute(self
, context
):
59 landmarks
= scene
.vr_landmarks
60 cam
= context
.view_layer
.objects
.active
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
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'}
79 def poll(cls
, context
):
80 return bpy
.types
.XrSessionState
.is_running(context
)
82 def execute(self
, context
):
84 landmarks
= scene
.vr_landmarks
85 wm
= context
.window_manager
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]
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'}
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
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
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'}
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
)
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
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'}
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
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
204 lm_pos
= lm
.base_pose_location
205 scene
.cursor
.location
= lm_pos
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
)
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'}
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
)
245 angle
= lm
.base_pose_angle
246 cam
.location
= lm
.base_pose_location
247 cam
.rotation_euler
= (math
.pi
/ 2, 0, angle
)
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(
263 def execute(self
, context
):
264 scene
= context
.scene
266 if self
.index
>= len(scene
.vr_landmarks
):
269 scene
.vr_landmarks_active
= (
270 self
.index
if self
.properties
.is_property_set(
271 "index") else scene
.vr_landmarks_selected
278 class VIEW3D_GT_vr_camera_cone(Gizmo
):
279 bl_idname
= "VIEW_3D_GT_vr_camera_cone"
283 def draw(self
, context
):
284 if not hasattr(self
, "frame_shape"):
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
= (
295 frame_shape_verts
[0],
297 frame_shape_verts
[1],
299 frame_shape_verts
[2],
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)
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
):
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
):
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'}
353 def poll(cls
, context
):
354 view3d
= context
.space_data
356 view3d
.shading
.vr_show_virtual_camera
and
357 bpy
.types
.XrSessionState
.is_running(context
) and
358 not view3d
.mirror_xr_session
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)
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
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'}
396 def poll(cls
, context
):
397 view3d
= context
.space_data
399 view3d
.shading
.vr_show_controllers
and
400 bpy
.types
.XrSessionState
.is_running(context
) and
401 not view3d
.mirror_xr_session
405 def _get_controller_pose_matrix(context
, idx
, is_grip
, scale
):
406 wm
= context
.window_manager
411 loc
= wm
.xr_session_state
.controller_grip_location_get(context
, idx
)
412 rot
= wm
.xr_session_state
.controller_grip_rotation_get(context
, idx
)
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
)))
420 transmat
= Matrix
.Translation(loc
)
421 scalemat
= Matrix
.Scale(scale
, 4)
423 return transmat
@ rotmat
@ scalemat
425 def setup(self
, context
):
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
435 def draw_prepare(self
, context
):
440 for gizmo
in self
.gizmos
:
441 is_grip
= (gizmo
.bl_idname
== VIEW3D_GT_vr_controller_grip
.bl_idname
)
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'}
461 def poll(cls
, context
):
462 view3d
= context
.space_data
464 view3d
.shading
.vr_show_landmarks
467 def setup(self
, context
):
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
479 if ((lm
.type == 'SCENE_CAMERA' and not scene
.camera
) or
480 (lm
.type == 'OBJECT' and not lm
.base_pose_object
)):
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
491 if lm
.type == '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
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
)
504 transmat
= Matrix
.Translation(lm
.base_pose_location
)
506 lm_mat
= transmat
@ rotmat
508 self
.gizmo
.matrix_basis
= lm_mat
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
,
534 bpy
.utils
.register_class(cls
)
539 bpy
.utils
.unregister_class(cls
)