1 # SPDX-FileCopyrightText: 2021-2023 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
7 importlib
.reload(properties
)
9 from . import properties
13 from bpy
.app
.translations
import pgettext_data
as data_
14 from bpy
.types
import (
20 from math
import radians
21 from mathutils
import Euler
, Matrix
, Quaternion
, Vector
25 class VIEW3D_OT_vr_landmark_add(Operator
):
26 bl_idname
= "view3d.vr_landmark_add"
27 bl_label
= "Add VR Landmark"
28 bl_description
= "Add a new VR landmark to the list and select it"
29 bl_options
= {'UNDO', 'REGISTER'}
31 def execute(self
, context
):
33 landmarks
= scene
.vr_landmarks
37 # select newly created set
38 scene
.vr_landmarks_selected
= len(landmarks
) - 1
43 class VIEW3D_OT_vr_landmark_from_camera(Operator
):
44 bl_idname
= "view3d.vr_landmark_from_camera"
45 bl_label
= "Add VR Landmark from Camera"
46 bl_description
= "Add a new VR landmark from the active camera object to the list and select it"
47 bl_options
= {'UNDO', 'REGISTER'}
50 def poll(cls
, context
):
53 vl_objects
= bpy
.context
.view_layer
.objects
54 if vl_objects
.active
and vl_objects
.active
.type == 'CAMERA':
58 def execute(self
, context
):
60 landmarks
= scene
.vr_landmarks
61 cam
= context
.view_layer
.objects
.active
64 lm
.base_pose_object
= cam
65 lm
.name
= "LM_" + cam
.name
67 # select newly created set
68 scene
.vr_landmarks_selected
= len(landmarks
) - 1
73 class VIEW3D_OT_vr_landmark_from_session(Operator
):
74 bl_idname
= "view3d.vr_landmark_from_session"
75 bl_label
= "Add VR Landmark from Session"
76 bl_description
= "Add VR landmark from the viewer pose of the running VR session to the list and select it"
77 bl_options
= {'UNDO', 'REGISTER'}
80 def poll(cls
, context
):
81 return bpy
.types
.XrSessionState
.is_running(context
)
83 def execute(self
, context
):
85 landmarks
= scene
.vr_landmarks
86 wm
= context
.window_manager
90 scene
.vr_landmarks_selected
= len(landmarks
) - 1
92 loc
= wm
.xr_session_state
.viewer_pose_location
93 rot
= wm
.xr_session_state
.viewer_pose_rotation
.to_euler()
95 lm
.base_pose_location
= loc
96 lm
.base_pose_angle
= rot
[2]
101 class VIEW3D_OT_vr_camera_landmark_from_session(Operator
):
102 bl_idname
= "view3d.vr_camera_landmark_from_session"
103 bl_label
= "Add Camera and VR Landmark from Session"
104 bl_description
= "Create a new Camera and VR Landmark from the viewer pose of the running VR session and select it"
105 bl_options
= {'UNDO', 'REGISTER'}
108 def poll(cls
, context
):
109 return bpy
.types
.XrSessionState
.is_running(context
)
111 def execute(self
, context
):
112 scene
= context
.scene
113 landmarks
= scene
.vr_landmarks
114 wm
= context
.window_manager
118 scene
.vr_landmarks_selected
= len(landmarks
) - 1
120 loc
= wm
.xr_session_state
.viewer_pose_location
121 rot
= wm
.xr_session_state
.viewer_pose_rotation
.to_euler()
123 cam
= bpy
.data
.cameras
.new(data_("Camera") + "_" + lm
.name
)
124 new_cam
= bpy
.data
.objects
.new(data_("Camera") + "_" + lm
.name
, cam
)
125 scene
.collection
.objects
.link(new_cam
)
126 new_cam
.location
= loc
127 new_cam
.rotation_euler
= rot
129 lm
.base_pose_object
= new_cam
134 class VIEW3D_OT_update_vr_landmark(Operator
):
135 bl_idname
= "view3d.update_vr_landmark"
136 bl_label
= "Update Custom VR Landmark"
137 bl_description
= "Update the selected landmark from the current viewer pose in the VR session"
138 bl_options
= {'UNDO', 'REGISTER'}
141 def poll(cls
, context
):
142 selected_landmark
= properties
.VRLandmark
.get_selected_landmark(context
)
143 return bpy
.types
.XrSessionState
.is_running(context
) and selected_landmark
.type == 'CUSTOM'
145 def execute(self
, context
):
146 wm
= context
.window_manager
148 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
150 loc
= wm
.xr_session_state
.viewer_pose_location
151 rot
= wm
.xr_session_state
.viewer_pose_rotation
.to_euler()
153 lm
.base_pose_location
= loc
154 lm
.base_pose_angle
= rot
156 # Re-activate the landmark to trigger viewer reset and flush landmark settings to the session settings.
157 properties
.vr_landmark_active_update(None, context
)
162 class VIEW3D_OT_vr_landmark_remove(Operator
):
163 bl_idname
= "view3d.vr_landmark_remove"
164 bl_label
= "Remove VR Landmark"
165 bl_description
= "Delete the selected VR landmark from the list"
166 bl_options
= {'UNDO', 'REGISTER'}
168 def execute(self
, context
):
169 scene
= context
.scene
170 landmarks
= scene
.vr_landmarks
172 if len(landmarks
) > 1:
173 landmark_selected_idx
= scene
.vr_landmarks_selected
174 landmarks
.remove(landmark_selected_idx
)
176 scene
.vr_landmarks_selected
-= 1
181 class VIEW3D_OT_cursor_to_vr_landmark(Operator
):
182 bl_idname
= "view3d.cursor_to_vr_landmark"
183 bl_label
= "Cursor to VR Landmark"
184 bl_description
= "Move the 3D Cursor to the selected VR Landmark"
185 bl_options
= {'UNDO', 'REGISTER'}
188 def poll(cls
, context
):
189 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
190 if lm
.type == 'SCENE_CAMERA':
191 return context
.scene
.camera
is not None
192 elif lm
.type == 'OBJECT':
193 return lm
.base_pose_object
is not None
197 def execute(self
, context
):
198 scene
= context
.scene
199 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
200 if lm
.type == 'SCENE_CAMERA':
201 lm_pos
= scene
.camera
.location
202 elif lm
.type == 'OBJECT':
203 lm_pos
= lm
.base_pose_object
.location
205 lm_pos
= lm
.base_pose_location
206 scene
.cursor
.location
= lm_pos
211 class VIEW3D_OT_add_camera_from_vr_landmark(Operator
):
212 bl_idname
= "view3d.add_camera_from_vr_landmark"
213 bl_label
= "New Camera from VR Landmark"
214 bl_description
= "Create a new Camera from the selected VR Landmark"
215 bl_options
= {'UNDO', 'REGISTER'}
217 def execute(self
, context
):
218 scene
= context
.scene
219 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
221 cam
= bpy
.data
.cameras
.new(data_("Camera") + "_" + lm
.name
)
222 new_cam
= bpy
.data
.objects
.new(data_("Camera") + "_" + lm
.name
, cam
)
223 scene
.collection
.objects
.link(new_cam
)
224 angle
= lm
.base_pose_angle
225 new_cam
.location
= lm
.base_pose_location
226 new_cam
.rotation_euler
= (math
.pi
/ 2, 0, angle
)
231 class VIEW3D_OT_camera_to_vr_landmark(Operator
):
232 bl_idname
= "view3d.camera_to_vr_landmark"
233 bl_label
= "Scene Camera to VR Landmark"
234 bl_description
= "Position the scene camera at the selected landmark"
235 bl_options
= {'UNDO', 'REGISTER'}
238 def poll(cls
, context
):
239 return context
.scene
.camera
is not None
241 def execute(self
, context
):
242 scene
= context
.scene
243 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
246 angle
= lm
.base_pose_angle
247 cam
.location
= lm
.base_pose_location
248 cam
.rotation_euler
= (math
.pi
/ 2, 0, angle
)
253 class VIEW3D_OT_vr_landmark_activate(Operator
):
254 bl_idname
= "view3d.vr_landmark_activate"
255 bl_label
= "Activate VR Landmark"
256 bl_description
= "Change to the selected VR landmark from the list"
257 bl_options
= {'UNDO', 'REGISTER'}
259 index
: bpy
.props
.IntProperty(
264 def execute(self
, context
):
265 scene
= context
.scene
267 if self
.index
>= len(scene
.vr_landmarks
):
270 scene
.vr_landmarks_active
= (
271 self
.index
if self
.properties
.is_property_set(
272 "index") else scene
.vr_landmarks_selected
279 class VIEW3D_GT_vr_camera_cone(Gizmo
):
280 bl_idname
= "VIEW_3D_GT_vr_camera_cone"
284 def draw(self
, context
):
285 if not hasattr(self
, "frame_shape"):
288 frame_shape_verts
= (
289 (-aspect
[0], -aspect
[1], -1.0),
290 (aspect
[0], -aspect
[1], -1.0),
291 (aspect
[0], aspect
[1], -1.0),
292 (-aspect
[0], aspect
[1], -1.0),
294 lines_shape_verts
= (
296 frame_shape_verts
[0],
298 frame_shape_verts
[1],
300 frame_shape_verts
[2],
302 frame_shape_verts
[3],
305 self
.frame_shape
= self
.new_custom_shape(
306 'LINE_LOOP', frame_shape_verts
)
307 self
.lines_shape
= self
.new_custom_shape(
308 'LINES', lines_shape_verts
)
310 # Ensure correct GL state (otherwise other gizmos might mess that up)
311 gpu
.state
.line_width_set(1.0)
312 gpu
.state
.blend_set('ALPHA')
314 self
.draw_custom_shape(self
.frame_shape
)
315 self
.draw_custom_shape(self
.lines_shape
)
318 class VIEW3D_GT_vr_controller_grip(Gizmo
):
319 bl_idname
= "VIEW_3D_GT_vr_controller_grip"
321 def draw(self
, context
):
322 gpu
.state
.line_width_set(1.0)
323 gpu
.state
.blend_set('ALPHA')
325 self
.color
= 0.422, 0.438, 0.446
326 self
.draw_preset_circle(self
.matrix_basis
, axis
='POS_X')
327 self
.draw_preset_circle(self
.matrix_basis
, axis
='POS_Y')
328 self
.draw_preset_circle(self
.matrix_basis
, axis
='POS_Z')
331 class VIEW3D_GT_vr_controller_aim(Gizmo
):
332 bl_idname
= "VIEW_3D_GT_vr_controller_aim"
334 def draw(self
, context
):
335 gpu
.state
.line_width_set(1.0)
336 gpu
.state
.blend_set('ALPHA')
338 self
.color
= 1.0, 0.2, 0.322
339 self
.draw_preset_arrow(self
.matrix_basis
, axis
='POS_X')
340 self
.color
= 0.545, 0.863, 0.0
341 self
.draw_preset_arrow(self
.matrix_basis
, axis
='POS_Y')
342 self
.color
= 0.157, 0.565, 1.0
343 self
.draw_preset_arrow(self
.matrix_basis
, axis
='POS_Z')
346 class VIEW3D_GGT_vr_viewer_pose(GizmoGroup
):
347 bl_idname
= "VIEW3D_GGT_vr_viewer_pose"
348 bl_label
= "VR Viewer Pose Indicator"
349 bl_space_type
= 'VIEW_3D'
350 bl_region_type
= 'WINDOW'
351 bl_options
= {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
354 def poll(cls
, context
):
355 view3d
= context
.space_data
357 view3d
.shading
.vr_show_virtual_camera
and
358 bpy
.types
.XrSessionState
.is_running(context
) and
359 not view3d
.mirror_xr_session
363 def _get_viewer_pose_matrix(context
):
364 wm
= context
.window_manager
366 loc
= wm
.xr_session_state
.viewer_pose_location
367 rot
= wm
.xr_session_state
.viewer_pose_rotation
369 rotmat
= Matrix
.Identity(3)
372 transmat
= Matrix
.Translation(loc
)
374 return transmat
@ rotmat
376 def setup(self
, context
):
377 gizmo
= self
.gizmos
.new(VIEW3D_GT_vr_camera_cone
.bl_idname
)
378 gizmo
.aspect
= 1 / 3, 1 / 4
380 gizmo
.color
= gizmo
.color_highlight
= 0.2, 0.6, 1.0
385 def draw_prepare(self
, context
):
386 self
.gizmo
.matrix_basis
= self
._get
_viewer
_pose
_matrix
(context
)
389 class VIEW3D_GGT_vr_controller_poses(GizmoGroup
):
390 bl_idname
= "VIEW3D_GGT_vr_controller_poses"
391 bl_label
= "VR Controller Poses Indicator"
392 bl_space_type
= 'VIEW_3D'
393 bl_region_type
= 'WINDOW'
394 bl_options
= {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
397 def poll(cls
, context
):
398 view3d
= context
.space_data
400 view3d
.shading
.vr_show_controllers
and
401 bpy
.types
.XrSessionState
.is_running(context
) and
402 not view3d
.mirror_xr_session
406 def _get_controller_pose_matrix(context
, idx
, is_grip
, scale
):
407 wm
= context
.window_manager
412 loc
= wm
.xr_session_state
.controller_grip_location_get(context
, idx
)
413 rot
= wm
.xr_session_state
.controller_grip_rotation_get(context
, idx
)
415 loc
= wm
.xr_session_state
.controller_aim_location_get(context
, idx
)
416 rot
= wm
.xr_session_state
.controller_aim_rotation_get(context
, idx
)
418 rotmat
= Matrix
.Identity(3)
419 rotmat
.rotate(Quaternion(Vector(rot
)))
421 transmat
= Matrix
.Translation(loc
)
422 scalemat
= Matrix
.Scale(scale
, 4)
424 return transmat
@ rotmat
@ scalemat
426 def setup(self
, context
):
428 self
.gizmos
.new(VIEW3D_GT_vr_controller_grip
.bl_idname
)
429 self
.gizmos
.new(VIEW3D_GT_vr_controller_aim
.bl_idname
)
431 for gizmo
in self
.gizmos
:
432 gizmo
.aspect
= 1 / 3, 1 / 4
433 gizmo
.color_highlight
= 1.0, 1.0, 1.0
436 def draw_prepare(self
, context
):
441 for gizmo
in self
.gizmos
:
442 is_grip
= (gizmo
.bl_idname
== VIEW3D_GT_vr_controller_grip
.bl_idname
)
451 gizmo
.matrix_basis
= self
._get
_controller
_pose
_matrix
(context
, idx
, is_grip
, scale
)
454 class VIEW3D_GGT_vr_landmarks(GizmoGroup
):
455 bl_idname
= "VIEW3D_GGT_vr_landmarks"
456 bl_label
= "VR Landmark Indicators"
457 bl_space_type
= 'VIEW_3D'
458 bl_region_type
= 'WINDOW'
459 bl_options
= {'3D', 'PERSISTENT', 'SCALE'}
462 def poll(cls
, context
):
463 view3d
= context
.space_data
465 view3d
.shading
.vr_show_landmarks
468 def setup(self
, context
):
471 def draw_prepare(self
, context
):
472 # first delete the old gizmos
473 for g
in self
.gizmos
:
474 self
.gizmos
.remove(g
)
476 scene
= context
.scene
477 landmarks
= scene
.vr_landmarks
480 if ((lm
.type == 'SCENE_CAMERA' and not scene
.camera
) or
481 (lm
.type == 'OBJECT' and not lm
.base_pose_object
)):
484 gizmo
= self
.gizmos
.new(VIEW3D_GT_vr_camera_cone
.bl_idname
)
485 gizmo
.aspect
= 1 / 3, 1 / 4
487 gizmo
.color
= gizmo
.color_highlight
= 0.2, 1.0, 0.6
492 if lm
.type == 'SCENE_CAMERA':
494 lm_mat
= cam
.matrix_world
if cam
else Matrix
.Identity(4)
495 elif lm
.type == 'OBJECT':
496 lm_mat
= lm
.base_pose_object
.matrix_world
498 angle
= lm
.base_pose_angle
499 raw_rot
= Euler((radians(90.0), 0, angle
))
501 rotmat
= Matrix
.Identity(3)
502 rotmat
.rotate(raw_rot
)
505 transmat
= Matrix
.Translation(lm
.base_pose_location
)
507 lm_mat
= transmat
@ rotmat
509 self
.gizmo
.matrix_basis
= lm_mat
513 VIEW3D_OT_vr_landmark_add
,
514 VIEW3D_OT_vr_landmark_remove
,
515 VIEW3D_OT_vr_landmark_activate
,
516 VIEW3D_OT_vr_landmark_from_session
,
517 VIEW3D_OT_vr_camera_landmark_from_session
,
518 VIEW3D_OT_add_camera_from_vr_landmark
,
519 VIEW3D_OT_camera_to_vr_landmark
,
520 VIEW3D_OT_vr_landmark_from_camera
,
521 VIEW3D_OT_cursor_to_vr_landmark
,
522 VIEW3D_OT_update_vr_landmark
,
524 VIEW3D_GT_vr_camera_cone
,
525 VIEW3D_GT_vr_controller_grip
,
526 VIEW3D_GT_vr_controller_aim
,
527 VIEW3D_GGT_vr_viewer_pose
,
528 VIEW3D_GGT_vr_controller_poses
,
529 VIEW3D_GGT_vr_landmarks
,
535 bpy
.utils
.register_class(cls
)
540 bpy
.utils
.unregister_class(cls
)