1 # SPDX-License-Identifier: GPL-2.0-or-later
4 from bpy
.types
import (
7 from bpy
.app
.handlers
import persistent
12 def vr_ensure_default_landmark(context
: bpy
.context
):
13 # Ensure there's a default landmark (scene camera by default).
14 landmarks
= bpy
.context
.scene
.vr_landmarks
17 landmarks
[0].type = 'SCENE_CAMERA'
20 def vr_landmark_active_type_update(self
, context
):
21 wm
= context
.window_manager
22 session_settings
= wm
.xr_session_settings
23 landmark_active
= VRLandmark
.get_active_landmark(context
)
25 # Update session's base pose type to the matching type.
26 if landmark_active
.type == 'SCENE_CAMERA':
27 session_settings
.base_pose_type
= 'SCENE_CAMERA'
28 elif landmark_active
.type == 'OBJECT':
29 session_settings
.base_pose_type
= 'OBJECT'
30 elif landmark_active
.type == 'CUSTOM':
31 session_settings
.base_pose_type
= 'CUSTOM'
34 def vr_landmark_active_base_pose_object_update(self
, context
):
35 session_settings
= context
.window_manager
.xr_session_settings
36 landmark_active
= VRLandmark
.get_active_landmark(context
)
38 # Update the anchor object to the (new) camera of this landmark.
39 session_settings
.base_pose_object
= landmark_active
.base_pose_object
42 def vr_landmark_active_base_pose_location_update(self
, context
):
43 session_settings
= context
.window_manager
.xr_session_settings
44 landmark_active
= VRLandmark
.get_active_landmark(context
)
46 session_settings
.base_pose_location
= landmark_active
.base_pose_location
49 def vr_landmark_active_base_pose_angle_update(self
, context
):
50 session_settings
= context
.window_manager
.xr_session_settings
51 landmark_active
= VRLandmark
.get_active_landmark(context
)
53 session_settings
.base_pose_angle
= landmark_active
.base_pose_angle
56 def vr_landmark_active_base_scale_update(self
, context
):
57 session_settings
= context
.window_manager
.xr_session_settings
58 landmark_active
= VRLandmark
.get_active_landmark(context
)
60 session_settings
.base_scale
= landmark_active
.base_scale
63 def vr_landmark_type_update(self
, context
):
64 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
65 landmark_active
= VRLandmark
.get_active_landmark(context
)
67 # Don't allow non-trivial base scale for scene camera landmarks.
68 if landmark_selected
.type == 'SCENE_CAMERA':
69 landmark_selected
.base_scale
= 1.0
71 # Only update session settings data if the changed landmark is actually
73 if landmark_active
== landmark_selected
:
74 vr_landmark_active_type_update(self
, context
)
77 def vr_landmark_base_pose_object_update(self
, context
):
78 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
79 landmark_active
= VRLandmark
.get_active_landmark(context
)
81 # Only update session settings data if the changed landmark is actually
83 if landmark_active
== landmark_selected
:
84 vr_landmark_active_base_pose_object_update(self
, context
)
87 def vr_landmark_base_pose_location_update(self
, context
):
88 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
89 landmark_active
= VRLandmark
.get_active_landmark(context
)
91 # Only update session settings data if the changed landmark is actually
93 if landmark_active
== landmark_selected
:
94 vr_landmark_active_base_pose_location_update(self
, context
)
97 def vr_landmark_base_pose_angle_update(self
, context
):
98 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
99 landmark_active
= VRLandmark
.get_active_landmark(context
)
101 # Only update session settings data if the changed landmark is actually
103 if landmark_active
== landmark_selected
:
104 vr_landmark_active_base_pose_angle_update(self
, context
)
107 def vr_landmark_base_scale_update(self
, context
):
108 landmark_selected
= VRLandmark
.get_selected_landmark(context
)
109 landmark_active
= VRLandmark
.get_active_landmark(context
)
111 # Only update session settings data if the changed landmark is actually
113 if landmark_active
== landmark_selected
:
114 vr_landmark_active_base_scale_update(self
, context
)
117 def vr_landmark_active_update(self
, context
):
118 wm
= context
.window_manager
120 vr_landmark_active_type_update(self
, context
)
121 vr_landmark_active_base_pose_object_update(self
, context
)
122 vr_landmark_active_base_pose_location_update(self
, context
)
123 vr_landmark_active_base_pose_angle_update(self
, context
)
124 vr_landmark_active_base_scale_update(self
, context
)
126 if wm
.xr_session_state
:
127 wm
.xr_session_state
.reset_to_base_pose(context
)
130 class VRLandmark(PropertyGroup
):
131 name
: bpy
.props
.StringProperty(
135 type: bpy
.props
.EnumProperty(
138 ('SCENE_CAMERA', "Scene Camera",
139 "Use scene's currently active camera to define the VR view base "
140 "location and rotation"),
141 ('OBJECT', "Custom Object",
142 "Use an existing object to define the VR view base location and "
144 ('CUSTOM', "Custom Pose",
145 "Allow a manually defined position and rotation to be used as "
146 "the VR view base pose"),
148 default
='SCENE_CAMERA',
149 update
=vr_landmark_type_update
,
151 base_pose_object
: bpy
.props
.PointerProperty(
153 type=bpy
.types
.Object
,
154 update
=vr_landmark_base_pose_object_update
,
156 base_pose_location
: bpy
.props
.FloatVectorProperty(
157 name
="Base Pose Location",
158 subtype
='TRANSLATION',
159 update
=vr_landmark_base_pose_location_update
,
161 base_pose_angle
: bpy
.props
.FloatProperty(
162 name
="Base Pose Angle",
164 update
=vr_landmark_base_pose_angle_update
,
166 base_scale
: bpy
.props
.FloatProperty(
168 description
="Viewer reference scale associated with this landmark",
171 update
=vr_landmark_base_scale_update
,
175 def get_selected_landmark(context
):
176 scene
= context
.scene
177 landmarks
= scene
.vr_landmarks
180 None if (len(landmarks
) <
181 1) else landmarks
[scene
.vr_landmarks_selected
]
185 def get_active_landmark(context
):
186 scene
= context
.scene
187 landmarks
= scene
.vr_landmarks
190 None if (len(landmarks
) <
191 1) else landmarks
[scene
.vr_landmarks_active
]
202 bpy
.utils
.register_class(cls
)
204 bpy
.types
.Scene
.vr_landmarks
= bpy
.props
.CollectionProperty(
208 bpy
.types
.Scene
.vr_landmarks_selected
= bpy
.props
.IntProperty(
209 name
="Selected Landmark"
211 bpy
.types
.Scene
.vr_landmarks_active
= bpy
.props
.IntProperty(
212 update
=vr_landmark_active_update
,
215 bpy
.app
.handlers
.load_post
.append(vr_ensure_default_landmark
)
220 bpy
.utils
.unregister_class(cls
)
222 del bpy
.types
.Scene
.vr_landmarks
223 del bpy
.types
.Scene
.vr_landmarks_selected
224 del bpy
.types
.Scene
.vr_landmarks_active
226 bpy
.app
.handlers
.load_post
.remove(vr_ensure_default_landmark
)