1 # SPDX-License-Identifier: GPL-2.0-or-later
5 importlib
.reload(properties
)
7 from . import properties
11 from bpy
.app
.translations
import pgettext_data
as data_
12 from bpy
.types
import (
18 from math
import radians
19 from mathutils
import Euler
, Matrix
, Quaternion
, Vector
23 class VIEW3D_OT_vr_landmark_add(Operator
):
24 bl_idname
= "view3d.vr_landmark_add"
25 bl_label
= "Add VR Landmark"
26 bl_description
= "Add a new VR landmark to the list and select it"
27 bl_options
= {'UNDO', 'REGISTER'}
29 def execute(self
, context
):
31 landmarks
= scene
.vr_landmarks
35 # select newly created set
36 scene
.vr_landmarks_selected
= len(landmarks
) - 1
41 class VIEW3D_OT_vr_landmark_from_camera(Operator
):
42 bl_idname
= "view3d.vr_landmark_from_camera"
43 bl_label
= "Add VR Landmark from Camera"
44 bl_description
= "Add a new VR landmark from the active camera object to the list and select it"
45 bl_options
= {'UNDO', 'REGISTER'}
48 def poll(cls
, context
):
51 vl_objects
= bpy
.context
.view_layer
.objects
52 if vl_objects
.active
and vl_objects
.active
.type == 'CAMERA':
56 def execute(self
, context
):
58 landmarks
= scene
.vr_landmarks
59 cam
= context
.view_layer
.objects
.active
62 lm
.base_pose_object
= cam
63 lm
.name
= "LM_" + cam
.name
65 # select newly created set
66 scene
.vr_landmarks_selected
= len(landmarks
) - 1
71 class VIEW3D_OT_vr_landmark_from_session(Operator
):
72 bl_idname
= "view3d.vr_landmark_from_session"
73 bl_label
= "Add VR Landmark from Session"
74 bl_description
= "Add VR landmark from the viewer pose of the running VR session to the list and select it"
75 bl_options
= {'UNDO', 'REGISTER'}
78 def poll(cls
, context
):
79 return bpy
.types
.XrSessionState
.is_running(context
)
81 def execute(self
, context
):
83 landmarks
= scene
.vr_landmarks
84 wm
= context
.window_manager
88 scene
.vr_landmarks_selected
= len(landmarks
) - 1
90 loc
= wm
.xr_session_state
.viewer_pose_location
91 rot
= wm
.xr_session_state
.viewer_pose_rotation
.to_euler()
93 lm
.base_pose_location
= loc
94 lm
.base_pose_angle
= rot
[2]
99 class VIEW3D_OT_vr_camera_landmark_from_session(Operator
):
100 bl_idname
= "view3d.vr_camera_landmark_from_session"
101 bl_label
= "Add Camera and VR Landmark from Session"
102 bl_description
= "Create a new Camera and VR Landmark from the viewer pose of the running VR session and select it"
103 bl_options
= {'UNDO', 'REGISTER'}
106 def poll(cls
, context
):
107 return bpy
.types
.XrSessionState
.is_running(context
)
109 def execute(self
, context
):
110 scene
= context
.scene
111 landmarks
= scene
.vr_landmarks
112 wm
= context
.window_manager
116 scene
.vr_landmarks_selected
= len(landmarks
) - 1
118 loc
= wm
.xr_session_state
.viewer_pose_location
119 rot
= wm
.xr_session_state
.viewer_pose_rotation
.to_euler()
121 cam
= bpy
.data
.cameras
.new(data_("Camera") + "_" + lm
.name
)
122 new_cam
= bpy
.data
.objects
.new(data_("Camera") + "_" + lm
.name
, cam
)
123 scene
.collection
.objects
.link(new_cam
)
124 new_cam
.location
= loc
125 new_cam
.rotation_euler
= rot
127 lm
.base_pose_object
= new_cam
132 class VIEW3D_OT_update_vr_landmark(Operator
):
133 bl_idname
= "view3d.update_vr_landmark"
134 bl_label
= "Update Custom VR Landmark"
135 bl_description
= "Update the selected landmark from the current viewer pose in the VR session"
136 bl_options
= {'UNDO', 'REGISTER'}
139 def poll(cls
, context
):
140 selected_landmark
= properties
.VRLandmark
.get_selected_landmark(context
)
141 return bpy
.types
.XrSessionState
.is_running(context
) and selected_landmark
.type == 'CUSTOM'
143 def execute(self
, context
):
144 wm
= context
.window_manager
146 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
148 loc
= wm
.xr_session_state
.viewer_pose_location
149 rot
= wm
.xr_session_state
.viewer_pose_rotation
.to_euler()
151 lm
.base_pose_location
= loc
152 lm
.base_pose_angle
= rot
154 # Re-activate the landmark to trigger viewer reset and flush landmark settings to the session settings.
155 properties
.vr_landmark_active_update(None, context
)
160 class VIEW3D_OT_vr_landmark_remove(Operator
):
161 bl_idname
= "view3d.vr_landmark_remove"
162 bl_label
= "Remove VR Landmark"
163 bl_description
= "Delete the selected VR landmark from the list"
164 bl_options
= {'UNDO', 'REGISTER'}
166 def execute(self
, context
):
167 scene
= context
.scene
168 landmarks
= scene
.vr_landmarks
170 if len(landmarks
) > 1:
171 landmark_selected_idx
= scene
.vr_landmarks_selected
172 landmarks
.remove(landmark_selected_idx
)
174 scene
.vr_landmarks_selected
-= 1
179 class VIEW3D_OT_cursor_to_vr_landmark(Operator
):
180 bl_idname
= "view3d.cursor_to_vr_landmark"
181 bl_label
= "Cursor to VR Landmark"
182 bl_description
= "Move the 3D Cursor to the selected VR Landmark"
183 bl_options
= {'UNDO', 'REGISTER'}
186 def poll(cls
, context
):
187 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
188 if lm
.type == 'SCENE_CAMERA':
189 return context
.scene
.camera
is not None
190 elif lm
.type == 'OBJECT':
191 return lm
.base_pose_object
is not None
195 def execute(self
, context
):
196 scene
= context
.scene
197 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
198 if lm
.type == 'SCENE_CAMERA':
199 lm_pos
= scene
.camera
.location
200 elif lm
.type == 'OBJECT':
201 lm_pos
= lm
.base_pose_object
.location
203 lm_pos
= lm
.base_pose_location
204 scene
.cursor
.location
= lm_pos
209 class VIEW3D_OT_add_camera_from_vr_landmark(Operator
):
210 bl_idname
= "view3d.add_camera_from_vr_landmark"
211 bl_label
= "New Camera from VR Landmark"
212 bl_description
= "Create a new Camera from the selected VR Landmark"
213 bl_options
= {'UNDO', 'REGISTER'}
215 def execute(self
, context
):
216 scene
= context
.scene
217 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
219 cam
= bpy
.data
.cameras
.new(data_("Camera") + "_" + lm
.name
)
220 new_cam
= bpy
.data
.objects
.new(data_("Camera") + "_" + lm
.name
, cam
)
221 scene
.collection
.objects
.link(new_cam
)
222 angle
= lm
.base_pose_angle
223 new_cam
.location
= lm
.base_pose_location
224 new_cam
.rotation_euler
= (math
.pi
/ 2, 0, angle
)
229 class VIEW3D_OT_camera_to_vr_landmark(Operator
):
230 bl_idname
= "view3d.camera_to_vr_landmark"
231 bl_label
= "Scene Camera to VR Landmark"
232 bl_description
= "Position the scene camera at the selected landmark"
233 bl_options
= {'UNDO', 'REGISTER'}
236 def poll(cls
, context
):
237 return context
.scene
.camera
is not None
239 def execute(self
, context
):
240 scene
= context
.scene
241 lm
= properties
.VRLandmark
.get_selected_landmark(context
)
244 angle
= lm
.base_pose_angle
245 cam
.location
= lm
.base_pose_location
246 cam
.rotation_euler
= (math
.pi
/ 2, 0, angle
)
251 class VIEW3D_OT_vr_landmark_activate(Operator
):
252 bl_idname
= "view3d.vr_landmark_activate"
253 bl_label
= "Activate VR Landmark"
254 bl_description
= "Change to the selected VR landmark from the list"
255 bl_options
= {'UNDO', 'REGISTER'}
257 index
: bpy
.props
.IntProperty(
262 def execute(self
, context
):
263 scene
= context
.scene
265 if self
.index
>= len(scene
.vr_landmarks
):
268 scene
.vr_landmarks_active
= (
269 self
.index
if self
.properties
.is_property_set(
270 "index") else scene
.vr_landmarks_selected
277 class VIEW3D_GT_vr_camera_cone(Gizmo
):
278 bl_idname
= "VIEW_3D_GT_vr_camera_cone"
282 def draw(self
, context
):
283 if not hasattr(self
, "frame_shape"):
286 frame_shape_verts
= (
287 (-aspect
[0], -aspect
[1], -1.0),
288 (aspect
[0], -aspect
[1], -1.0),
289 (aspect
[0], aspect
[1], -1.0),
290 (-aspect
[0], aspect
[1], -1.0),
292 lines_shape_verts
= (
294 frame_shape_verts
[0],
296 frame_shape_verts
[1],
298 frame_shape_verts
[2],
300 frame_shape_verts
[3],
303 self
.frame_shape
= self
.new_custom_shape(
304 'LINE_LOOP', frame_shape_verts
)
305 self
.lines_shape
= self
.new_custom_shape(
306 'LINES', lines_shape_verts
)
308 # Ensure correct GL state (otherwise other gizmos might mess that up)
309 gpu
.state
.line_width_set(1.0)
310 gpu
.state
.blend_set('ALPHA')
312 self
.draw_custom_shape(self
.frame_shape
)
313 self
.draw_custom_shape(self
.lines_shape
)
316 class VIEW3D_GT_vr_controller_grip(Gizmo
):
317 bl_idname
= "VIEW_3D_GT_vr_controller_grip"
319 def draw(self
, context
):
320 gpu
.state
.line_width_set(1.0)
321 gpu
.state
.blend_set('ALPHA')
323 self
.color
= 0.422, 0.438, 0.446
324 self
.draw_preset_circle(self
.matrix_basis
, axis
='POS_X')
325 self
.draw_preset_circle(self
.matrix_basis
, axis
='POS_Y')
326 self
.draw_preset_circle(self
.matrix_basis
, axis
='POS_Z')
329 class VIEW3D_GT_vr_controller_aim(Gizmo
):
330 bl_idname
= "VIEW_3D_GT_vr_controller_aim"
332 def draw(self
, context
):
333 gpu
.state
.line_width_set(1.0)
334 gpu
.state
.blend_set('ALPHA')
336 self
.color
= 1.0, 0.2, 0.322
337 self
.draw_preset_arrow(self
.matrix_basis
, axis
='POS_X')
338 self
.color
= 0.545, 0.863, 0.0
339 self
.draw_preset_arrow(self
.matrix_basis
, axis
='POS_Y')
340 self
.color
= 0.157, 0.565, 1.0
341 self
.draw_preset_arrow(self
.matrix_basis
, axis
='POS_Z')
344 class VIEW3D_GGT_vr_viewer_pose(GizmoGroup
):
345 bl_idname
= "VIEW3D_GGT_vr_viewer_pose"
346 bl_label
= "VR Viewer Pose Indicator"
347 bl_space_type
= 'VIEW_3D'
348 bl_region_type
= 'WINDOW'
349 bl_options
= {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
352 def poll(cls
, context
):
353 view3d
= context
.space_data
355 view3d
.shading
.vr_show_virtual_camera
and
356 bpy
.types
.XrSessionState
.is_running(context
) and
357 not view3d
.mirror_xr_session
361 def _get_viewer_pose_matrix(context
):
362 wm
= context
.window_manager
364 loc
= wm
.xr_session_state
.viewer_pose_location
365 rot
= wm
.xr_session_state
.viewer_pose_rotation
367 rotmat
= Matrix
.Identity(3)
370 transmat
= Matrix
.Translation(loc
)
372 return transmat
@ rotmat
374 def setup(self
, context
):
375 gizmo
= self
.gizmos
.new(VIEW3D_GT_vr_camera_cone
.bl_idname
)
376 gizmo
.aspect
= 1 / 3, 1 / 4
378 gizmo
.color
= gizmo
.color_highlight
= 0.2, 0.6, 1.0
383 def draw_prepare(self
, context
):
384 self
.gizmo
.matrix_basis
= self
._get
_viewer
_pose
_matrix
(context
)
387 class VIEW3D_GGT_vr_controller_poses(GizmoGroup
):
388 bl_idname
= "VIEW3D_GGT_vr_controller_poses"
389 bl_label
= "VR Controller Poses Indicator"
390 bl_space_type
= 'VIEW_3D'
391 bl_region_type
= 'WINDOW'
392 bl_options
= {'3D', 'PERSISTENT', 'SCALE', 'VR_REDRAWS'}
395 def poll(cls
, context
):
396 view3d
= context
.space_data
398 view3d
.shading
.vr_show_controllers
and
399 bpy
.types
.XrSessionState
.is_running(context
) and
400 not view3d
.mirror_xr_session
404 def _get_controller_pose_matrix(context
, idx
, is_grip
, scale
):
405 wm
= context
.window_manager
410 loc
= wm
.xr_session_state
.controller_grip_location_get(context
, idx
)
411 rot
= wm
.xr_session_state
.controller_grip_rotation_get(context
, idx
)
413 loc
= wm
.xr_session_state
.controller_aim_location_get(context
, idx
)
414 rot
= wm
.xr_session_state
.controller_aim_rotation_get(context
, idx
)
416 rotmat
= Matrix
.Identity(3)
417 rotmat
.rotate(Quaternion(Vector(rot
)))
419 transmat
= Matrix
.Translation(loc
)
420 scalemat
= Matrix
.Scale(scale
, 4)
422 return transmat
@ rotmat
@ scalemat
424 def setup(self
, context
):
426 self
.gizmos
.new(VIEW3D_GT_vr_controller_grip
.bl_idname
)
427 self
.gizmos
.new(VIEW3D_GT_vr_controller_aim
.bl_idname
)
429 for gizmo
in self
.gizmos
:
430 gizmo
.aspect
= 1 / 3, 1 / 4
431 gizmo
.color_highlight
= 1.0, 1.0, 1.0
434 def draw_prepare(self
, context
):
439 for gizmo
in self
.gizmos
:
440 is_grip
= (gizmo
.bl_idname
== VIEW3D_GT_vr_controller_grip
.bl_idname
)
449 gizmo
.matrix_basis
= self
._get
_controller
_pose
_matrix
(context
, idx
, is_grip
, scale
)
452 class VIEW3D_GGT_vr_landmarks(GizmoGroup
):
453 bl_idname
= "VIEW3D_GGT_vr_landmarks"
454 bl_label
= "VR Landmark Indicators"
455 bl_space_type
= 'VIEW_3D'
456 bl_region_type
= 'WINDOW'
457 bl_options
= {'3D', 'PERSISTENT', 'SCALE'}
460 def poll(cls
, context
):
461 view3d
= context
.space_data
463 view3d
.shading
.vr_show_landmarks
466 def setup(self
, context
):
469 def draw_prepare(self
, context
):
470 # first delete the old gizmos
471 for g
in self
.gizmos
:
472 self
.gizmos
.remove(g
)
474 scene
= context
.scene
475 landmarks
= scene
.vr_landmarks
478 if ((lm
.type == 'SCENE_CAMERA' and not scene
.camera
) or
479 (lm
.type == 'OBJECT' and not lm
.base_pose_object
)):
482 gizmo
= self
.gizmos
.new(VIEW3D_GT_vr_camera_cone
.bl_idname
)
483 gizmo
.aspect
= 1 / 3, 1 / 4
485 gizmo
.color
= gizmo
.color_highlight
= 0.2, 1.0, 0.6
490 if lm
.type == 'SCENE_CAMERA':
492 lm_mat
= cam
.matrix_world
if cam
else Matrix
.Identity(4)
493 elif lm
.type == 'OBJECT':
494 lm_mat
= lm
.base_pose_object
.matrix_world
496 angle
= lm
.base_pose_angle
497 raw_rot
= Euler((radians(90.0), 0, angle
))
499 rotmat
= Matrix
.Identity(3)
500 rotmat
.rotate(raw_rot
)
503 transmat
= Matrix
.Translation(lm
.base_pose_location
)
505 lm_mat
= transmat
@ rotmat
507 self
.gizmo
.matrix_basis
= lm_mat
511 VIEW3D_OT_vr_landmark_add
,
512 VIEW3D_OT_vr_landmark_remove
,
513 VIEW3D_OT_vr_landmark_activate
,
514 VIEW3D_OT_vr_landmark_from_session
,
515 VIEW3D_OT_vr_camera_landmark_from_session
,
516 VIEW3D_OT_add_camera_from_vr_landmark
,
517 VIEW3D_OT_camera_to_vr_landmark
,
518 VIEW3D_OT_vr_landmark_from_camera
,
519 VIEW3D_OT_cursor_to_vr_landmark
,
520 VIEW3D_OT_update_vr_landmark
,
522 VIEW3D_GT_vr_camera_cone
,
523 VIEW3D_GT_vr_controller_grip
,
524 VIEW3D_GT_vr_controller_aim
,
525 VIEW3D_GGT_vr_viewer_pose
,
526 VIEW3D_GGT_vr_controller_poses
,
527 VIEW3D_GGT_vr_landmarks
,
533 bpy
.utils
.register_class(cls
)
538 bpy
.utils
.unregister_class(cls
)