1 # SPDX-License-Identifier: GPL-2.0-or-later
6 from bpy
.types
import (
9 from bpy
.app
.handlers
import persistent
14 def vr_ensure_default_landmark(context
: bpy
.context
):
15 # Ensure there's a default landmark (scene camera by default).
16 landmarks
= bpy
.context
.scene
.vr_landmarks
19 landmarks
[0].type = 'SCENE_CAMERA'
22 def vr_landmark_active_type_update(self
, context
):
23 wm
= context
.window_manager
24 session_settings
= wm
.xr_session_settings
25 landmark_active
= VRLandmark
.get_active_landmark(context
)
27 # Update session's base pose type to the matching type.
28 if landmark_active
.type == 'SCENE_CAMERA':
29 session_settings
.base_pose_type
= 'SCENE_CAMERA'
30 elif landmark_active
.type == 'OBJECT':
31 session_settings
.base_pose_type
= 'OBJECT'
32 elif landmark_active
.type == 'CUSTOM':
33 session_settings
.base_pose_type
= 'CUSTOM'
36 def vr_landmark_active_base_pose_object_update(self
, context
):
37 session_settings
= context
.window_manager
.xr_session_settings
38 landmark_active
= VRLandmark
.get_active_landmark(context
)
40 # Update the anchor object to the (new) camera of this landmark.
41 session_settings
.base_pose_object
= landmark_active
.base_pose_object
44 def vr_landmark_active_base_pose_location_update(self
, context
):
45 session_settings
= context
.window_manager
.xr_session_settings
46 landmark_active
= VRLandmark
.get_active_landmark(context
)
48 session_settings
.base_pose_location
= landmark_active
.base_pose_location
51 def vr_landmark_active_base_pose_angle_update(self
, context
):
52 session_settings
= context
.window_manager
.xr_session_settings
53 landmark_active
= VRLandmark
.get_active_landmark(context
)
55 session_settings
.base_pose_angle
= landmark_active
.base_pose_angle
58 def vr_landmark_active_base_scale_update(self
, context
):
59 session_settings
= context
.window_manager
.xr_session_settings
60 landmark_active
= VRLandmark
.get_active_landmark(context
)
62 session_settings
.base_scale
= landmark_active
.base_scale
65 def vr_landmark_type_update(self
, context
):
66 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
67 landmark_active
= VRLandmark
.get_active_landmark(context
)
69 # Don't allow non-trivial base scale for scene camera landmarks.
70 if landmark_selected
.type == 'SCENE_CAMERA':
71 landmark_selected
.base_scale
= 1.0
73 # Only update session settings data if the changed landmark is actually
75 if landmark_active
== landmark_selected
:
76 vr_landmark_active_type_update(self
, context
)
79 def vr_landmark_base_pose_object_update(self
, context
):
80 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
81 landmark_active
= VRLandmark
.get_active_landmark(context
)
83 # Only update session settings data if the changed landmark is actually
85 if landmark_active
== landmark_selected
:
86 vr_landmark_active_base_pose_object_update(self
, context
)
89 def vr_landmark_base_pose_location_update(self
, context
):
90 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
91 landmark_active
= VRLandmark
.get_active_landmark(context
)
93 # Only update session settings data if the changed landmark is actually
95 if landmark_active
== landmark_selected
:
96 vr_landmark_active_base_pose_location_update(self
, context
)
99 def vr_landmark_base_pose_angle_update(self
, context
):
100 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
101 landmark_active
= VRLandmark
.get_active_landmark(context
)
103 # Only update session settings data if the changed landmark is actually
105 if landmark_active
== landmark_selected
:
106 vr_landmark_active_base_pose_angle_update(self
, context
)
109 def vr_landmark_base_scale_update(self
, context
):
110 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
111 landmark_active
= VRLandmark
.get_active_landmark(context
)
113 # Only update session settings data if the changed landmark is actually
115 if landmark_active
== landmark_selected
:
116 vr_landmark_active_base_scale_update(self
, context
)
119 def vr_landmark_active_update(self
, context
):
120 wm
= context
.window_manager
122 vr_landmark_active_type_update(self
, context
)
123 vr_landmark_active_base_pose_object_update(self
, context
)
124 vr_landmark_active_base_pose_location_update(self
, context
)
125 vr_landmark_active_base_pose_angle_update(self
, context
)
126 vr_landmark_active_base_scale_update(self
, context
)
128 if wm
.xr_session_state
:
129 wm
.xr_session_state
.reset_to_base_pose(context
)
132 class VRLandmark(PropertyGroup
):
133 name
: bpy
.props
.StringProperty(
137 type: bpy
.props
.EnumProperty(
140 ('SCENE_CAMERA', "Scene Camera",
141 "Use scene's currently active camera to define the VR view base "
142 "location and rotation"),
143 ('OBJECT', "Custom Object",
144 "Use an existing object to define the VR view base location and "
146 ('CUSTOM', "Custom Pose",
147 "Allow a manually defined position and rotation to be used as "
148 "the VR view base pose"),
150 default
='SCENE_CAMERA',
151 update
=vr_landmark_type_update
,
153 base_pose_object
: bpy
.props
.PointerProperty(
155 type=bpy
.types
.Object
,
156 update
=vr_landmark_base_pose_object_update
,
158 base_pose_location
: bpy
.props
.FloatVectorProperty(
159 name
="Base Pose Location",
160 subtype
='TRANSLATION',
161 update
=vr_landmark_base_pose_location_update
,
163 base_pose_angle
: bpy
.props
.FloatProperty(
164 name
="Base Pose Angle",
166 update
=vr_landmark_base_pose_angle_update
,
168 base_scale
: bpy
.props
.FloatProperty(
170 description
="Viewer reference scale associated with this landmark",
173 update
=vr_landmark_base_scale_update
,
177 def get_selected_landmark(context
):
178 scene
= context
.scene
179 landmarks
= scene
.vr_landmarks
182 None if (len(landmarks
) <
183 1) else landmarks
[scene
.vr_landmarks_selected
]
187 def get_active_landmark(context
):
188 scene
= context
.scene
189 landmarks
= scene
.vr_landmarks
192 None if (len(landmarks
) <
193 1) else landmarks
[scene
.vr_landmarks_active
]
204 bpy
.utils
.register_class(cls
)
206 bpy
.types
.Scene
.vr_landmarks
= bpy
.props
.CollectionProperty(
210 bpy
.types
.Scene
.vr_landmarks_selected
= bpy
.props
.IntProperty(
211 name
="Selected Landmark"
213 bpy
.types
.Scene
.vr_landmarks_active
= bpy
.props
.IntProperty(
214 update
=vr_landmark_active_update
,
217 bpy
.app
.handlers
.load_post
.append(vr_ensure_default_landmark
)
222 bpy
.utils
.unregister_class(cls
)
224 del bpy
.types
.Scene
.vr_landmarks
225 del bpy
.types
.Scene
.vr_landmarks_selected
226 del bpy
.types
.Scene
.vr_landmarks_active
228 bpy
.app
.handlers
.load_post
.remove(vr_ensure_default_landmark
)