Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/openxr/openxr_interface.cpp
10277 views
1
/**************************************************************************/
2
/* openxr_interface.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "openxr_interface.h"
32
33
#include "core/io/resource_loader.h"
34
#include "core/io/resource_saver.h"
35
36
#include "extensions/openxr_eye_gaze_interaction.h"
37
#include "extensions/openxr_hand_interaction_extension.h"
38
#include "extensions/openxr_performance_settings_extension.h"
39
#include "servers/rendering/renderer_compositor.h"
40
41
#include <openxr/openxr.h>
42
43
void OpenXRInterface::_bind_methods() {
44
// lifecycle signals
45
ADD_SIGNAL(MethodInfo("session_begun"));
46
ADD_SIGNAL(MethodInfo("session_stopping"));
47
ADD_SIGNAL(MethodInfo("session_synchronized"));
48
ADD_SIGNAL(MethodInfo("session_focussed"));
49
ADD_SIGNAL(MethodInfo("session_visible"));
50
ADD_SIGNAL(MethodInfo("session_loss_pending"));
51
ADD_SIGNAL(MethodInfo("instance_exiting"));
52
ADD_SIGNAL(MethodInfo("pose_recentered"));
53
ADD_SIGNAL(MethodInfo("refresh_rate_changed", PropertyInfo(Variant::FLOAT, "refresh_rate")));
54
55
ADD_SIGNAL(MethodInfo("cpu_level_changed", PropertyInfo(Variant::INT, "sub_domain"), PropertyInfo(Variant::INT, "from_level"), PropertyInfo(Variant::INT, "to_level")));
56
ADD_SIGNAL(MethodInfo("gpu_level_changed", PropertyInfo(Variant::INT, "sub_domain"), PropertyInfo(Variant::INT, "from_level"), PropertyInfo(Variant::INT, "to_level")));
57
58
// State
59
ClassDB::bind_method(D_METHOD("get_session_state"), &OpenXRInterface::get_session_state);
60
61
// Display refresh rate
62
ClassDB::bind_method(D_METHOD("get_display_refresh_rate"), &OpenXRInterface::get_display_refresh_rate);
63
ClassDB::bind_method(D_METHOD("set_display_refresh_rate", "refresh_rate"), &OpenXRInterface::set_display_refresh_rate);
64
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "display_refresh_rate"), "set_display_refresh_rate", "get_display_refresh_rate");
65
66
// Render Target size multiplier
67
ClassDB::bind_method(D_METHOD("get_render_target_size_multiplier"), &OpenXRInterface::get_render_target_size_multiplier);
68
ClassDB::bind_method(D_METHOD("set_render_target_size_multiplier", "multiplier"), &OpenXRInterface::set_render_target_size_multiplier);
69
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "render_target_size_multiplier"), "set_render_target_size_multiplier", "get_render_target_size_multiplier");
70
71
// Foveation level
72
ClassDB::bind_method(D_METHOD("is_foveation_supported"), &OpenXRInterface::is_foveation_supported);
73
74
ClassDB::bind_method(D_METHOD("get_foveation_level"), &OpenXRInterface::get_foveation_level);
75
ClassDB::bind_method(D_METHOD("set_foveation_level", "foveation_level"), &OpenXRInterface::set_foveation_level);
76
ADD_PROPERTY(PropertyInfo(Variant::INT, "foveation_level"), "set_foveation_level", "get_foveation_level");
77
78
ClassDB::bind_method(D_METHOD("get_foveation_dynamic"), &OpenXRInterface::get_foveation_dynamic);
79
ClassDB::bind_method(D_METHOD("set_foveation_dynamic", "foveation_dynamic"), &OpenXRInterface::set_foveation_dynamic);
80
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "foveation_dynamic"), "set_foveation_dynamic", "get_foveation_dynamic");
81
82
// Action sets
83
ClassDB::bind_method(D_METHOD("is_action_set_active", "name"), &OpenXRInterface::is_action_set_active);
84
ClassDB::bind_method(D_METHOD("set_action_set_active", "name", "active"), &OpenXRInterface::set_action_set_active);
85
ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRInterface::get_action_sets);
86
87
// Refresh rates
88
ClassDB::bind_method(D_METHOD("get_available_display_refresh_rates"), &OpenXRInterface::get_available_display_refresh_rates);
89
90
// Hand tracking.
91
ClassDB::bind_method(D_METHOD("set_motion_range", "hand", "motion_range"), &OpenXRInterface::set_motion_range);
92
ClassDB::bind_method(D_METHOD("get_motion_range", "hand"), &OpenXRInterface::get_motion_range);
93
94
ClassDB::bind_method(D_METHOD("get_hand_tracking_source", "hand"), &OpenXRInterface::get_hand_tracking_source);
95
96
ClassDB::bind_method(D_METHOD("get_hand_joint_flags", "hand", "joint"), &OpenXRInterface::get_hand_joint_flags);
97
98
ClassDB::bind_method(D_METHOD("get_hand_joint_rotation", "hand", "joint"), &OpenXRInterface::get_hand_joint_rotation);
99
ClassDB::bind_method(D_METHOD("get_hand_joint_position", "hand", "joint"), &OpenXRInterface::get_hand_joint_position);
100
ClassDB::bind_method(D_METHOD("get_hand_joint_radius", "hand", "joint"), &OpenXRInterface::get_hand_joint_radius);
101
102
ClassDB::bind_method(D_METHOD("get_hand_joint_linear_velocity", "hand", "joint"), &OpenXRInterface::get_hand_joint_linear_velocity);
103
ClassDB::bind_method(D_METHOD("get_hand_joint_angular_velocity", "hand", "joint"), &OpenXRInterface::get_hand_joint_angular_velocity);
104
105
ClassDB::bind_method(D_METHOD("is_hand_tracking_supported"), &OpenXRInterface::is_hand_tracking_supported);
106
ClassDB::bind_method(D_METHOD("is_hand_interaction_supported"), &OpenXRInterface::is_hand_interaction_supported);
107
ClassDB::bind_method(D_METHOD("is_eye_gaze_interaction_supported"), &OpenXRInterface::is_eye_gaze_interaction_supported);
108
109
// VRS
110
ClassDB::bind_method(D_METHOD("get_vrs_min_radius"), &OpenXRInterface::get_vrs_min_radius);
111
ClassDB::bind_method(D_METHOD("set_vrs_min_radius", "radius"), &OpenXRInterface::set_vrs_min_radius);
112
ClassDB::bind_method(D_METHOD("get_vrs_strength"), &OpenXRInterface::get_vrs_strength);
113
ClassDB::bind_method(D_METHOD("set_vrs_strength", "strength"), &OpenXRInterface::set_vrs_strength);
114
115
// Performance settings.
116
ClassDB::bind_method(D_METHOD("set_cpu_level", "level"), &OpenXRInterface::set_cpu_level);
117
ClassDB::bind_method(D_METHOD("set_gpu_level", "level"), &OpenXRInterface::set_gpu_level);
118
119
ADD_GROUP("Vulkan VRS", "vrs_");
120
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_min_radius", PROPERTY_HINT_RANGE, "1.0,100.0,1.0"), "set_vrs_min_radius", "get_vrs_min_radius");
121
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_strength", PROPERTY_HINT_RANGE, "0.1,10.0,0.1"), "set_vrs_strength", "get_vrs_strength");
122
123
BIND_ENUM_CONSTANT(SESSION_STATE_UNKNOWN);
124
BIND_ENUM_CONSTANT(SESSION_STATE_IDLE);
125
BIND_ENUM_CONSTANT(SESSION_STATE_READY);
126
BIND_ENUM_CONSTANT(SESSION_STATE_SYNCHRONIZED);
127
BIND_ENUM_CONSTANT(SESSION_STATE_VISIBLE);
128
BIND_ENUM_CONSTANT(SESSION_STATE_FOCUSED);
129
BIND_ENUM_CONSTANT(SESSION_STATE_STOPPING);
130
BIND_ENUM_CONSTANT(SESSION_STATE_LOSS_PENDING);
131
BIND_ENUM_CONSTANT(SESSION_STATE_EXITING);
132
133
BIND_ENUM_CONSTANT(HAND_LEFT);
134
BIND_ENUM_CONSTANT(HAND_RIGHT);
135
BIND_ENUM_CONSTANT(HAND_MAX);
136
137
BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_UNOBSTRUCTED);
138
BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER);
139
BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_MAX);
140
141
BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_UNKNOWN);
142
BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_UNOBSTRUCTED);
143
BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_CONTROLLER);
144
BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_MAX);
145
146
BIND_ENUM_CONSTANT(HAND_JOINT_PALM);
147
BIND_ENUM_CONSTANT(HAND_JOINT_WRIST);
148
BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_METACARPAL);
149
BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_PROXIMAL);
150
BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_DISTAL);
151
BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_TIP);
152
BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_METACARPAL);
153
BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_PROXIMAL);
154
BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_INTERMEDIATE);
155
BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_DISTAL);
156
BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_TIP);
157
BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_METACARPAL);
158
BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_PROXIMAL);
159
BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_INTERMEDIATE);
160
BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_DISTAL);
161
BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_TIP);
162
BIND_ENUM_CONSTANT(HAND_JOINT_RING_METACARPAL);
163
BIND_ENUM_CONSTANT(HAND_JOINT_RING_PROXIMAL);
164
BIND_ENUM_CONSTANT(HAND_JOINT_RING_INTERMEDIATE);
165
BIND_ENUM_CONSTANT(HAND_JOINT_RING_DISTAL);
166
BIND_ENUM_CONSTANT(HAND_JOINT_RING_TIP);
167
BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_METACARPAL);
168
BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_PROXIMAL);
169
BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_INTERMEDIATE);
170
BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_DISTAL);
171
BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_TIP);
172
BIND_ENUM_CONSTANT(HAND_JOINT_MAX);
173
174
BIND_ENUM_CONSTANT(PERF_SETTINGS_LEVEL_POWER_SAVINGS);
175
BIND_ENUM_CONSTANT(PERF_SETTINGS_LEVEL_SUSTAINED_LOW);
176
BIND_ENUM_CONSTANT(PERF_SETTINGS_LEVEL_SUSTAINED_HIGH);
177
BIND_ENUM_CONSTANT(PERF_SETTINGS_LEVEL_BOOST);
178
179
BIND_ENUM_CONSTANT(PERF_SETTINGS_SUB_DOMAIN_COMPOSITING);
180
BIND_ENUM_CONSTANT(PERF_SETTINGS_SUB_DOMAIN_RENDERING);
181
BIND_ENUM_CONSTANT(PERF_SETTINGS_SUB_DOMAIN_THERMAL);
182
183
BIND_ENUM_CONSTANT(PERF_SETTINGS_NOTIF_LEVEL_NORMAL);
184
BIND_ENUM_CONSTANT(PERF_SETTINGS_NOTIF_LEVEL_WARNING);
185
BIND_ENUM_CONSTANT(PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED);
186
187
BIND_BITFIELD_FLAG(HAND_JOINT_NONE);
188
BIND_BITFIELD_FLAG(HAND_JOINT_ORIENTATION_VALID);
189
BIND_BITFIELD_FLAG(HAND_JOINT_ORIENTATION_TRACKED);
190
BIND_BITFIELD_FLAG(HAND_JOINT_POSITION_VALID);
191
BIND_BITFIELD_FLAG(HAND_JOINT_POSITION_TRACKED);
192
BIND_BITFIELD_FLAG(HAND_JOINT_LINEAR_VELOCITY_VALID);
193
BIND_BITFIELD_FLAG(HAND_JOINT_ANGULAR_VELOCITY_VALID);
194
}
195
196
StringName OpenXRInterface::get_name() const {
197
return StringName("OpenXR");
198
}
199
200
uint32_t OpenXRInterface::get_capabilities() const {
201
return XRInterface::XR_VR + XRInterface::XR_STEREO;
202
}
203
204
PackedStringArray OpenXRInterface::get_suggested_tracker_names() const {
205
// These are hardcoded in OpenXR, note that they will only be available if added to our action map
206
207
PackedStringArray arr = {
208
"head", // XRPositionalTracker for the users head (Mapped from OpenXR /user/head)
209
"left_hand", // XRControllerTracker for the users left hand (Mapped from OpenXR /user/hand/left)
210
"right_hand", // XRControllerTracker for the users right hand (Mapped from OpenXR /user/hand/right)
211
"/user/hand_tracker/left", // XRHandTracker for the users left hand
212
"/user/hand_tracker/right", // XRHandTracker for the users right hand
213
"/user/body_tracker", // XRBodyTracker for the users body
214
"/user/face_tracker", // XRFaceTracker for the users face
215
"/user/treadmill"
216
};
217
218
for (OpenXRExtensionWrapper *wrapper : OpenXRAPI::get_singleton()->get_registered_extension_wrappers()) {
219
arr.append_array(wrapper->get_suggested_tracker_names());
220
}
221
222
return arr;
223
}
224
225
XRInterface::TrackingStatus OpenXRInterface::get_tracking_status() const {
226
return tracking_state;
227
}
228
229
void OpenXRInterface::_load_action_map() {
230
ERR_FAIL_NULL(openxr_api);
231
232
// This may seem a bit duplicitous to a little bit of background info here.
233
// OpenXRActionMap (with all its sub resource classes) is a class that allows us to configure and store an action map in.
234
// This gives the user the ability to edit the action map in a UI and customize the actions.
235
// OpenXR however requires us to submit an action map and it takes over from that point and we can no longer change it.
236
// This system does that push and we store the info needed to then work with this action map going forward.
237
238
// Within our openxr device we maintain a number of classes that wrap the relevant OpenXR objects for this.
239
// Within OpenXRInterface we have a few internal classes that keep track of what we've created.
240
// This allow us to process the relevant actions each frame.
241
242
// just in case clean up
243
free_trackers();
244
free_interaction_profiles();
245
free_action_sets();
246
247
Ref<OpenXRActionMap> action_map;
248
if (Engine::get_singleton()->is_editor_hint()) {
249
#ifdef TOOLS_ENABLED
250
action_map.instantiate();
251
action_map->create_editor_action_sets();
252
#endif
253
} else {
254
String default_tres_name = openxr_api->get_default_action_map_resource_name();
255
256
// Check if we can load our default
257
if (ResourceLoader::exists(default_tres_name)) {
258
action_map = ResourceLoader::load(default_tres_name);
259
}
260
261
// Check if we need to create default action set
262
if (action_map.is_null()) {
263
action_map.instantiate();
264
action_map->create_default_action_sets();
265
#ifdef TOOLS_ENABLED
266
// Save our action sets so our user can
267
action_map->set_path(default_tres_name, true);
268
ResourceSaver::save(action_map, default_tres_name);
269
#endif
270
}
271
}
272
273
// process our action map
274
if (action_map.is_valid()) {
275
HashMap<Ref<OpenXRAction>, Action *> xr_actions;
276
277
Array action_set_array = action_map->get_action_sets();
278
for (int i = 0; i < action_set_array.size(); i++) {
279
// Create our action set
280
Ref<OpenXRActionSet> xr_action_set = action_set_array[i];
281
ActionSet *action_set = create_action_set(xr_action_set->get_name(), xr_action_set->get_localized_name(), xr_action_set->get_priority());
282
if (!action_set) {
283
continue;
284
}
285
286
// Now create our actions for these
287
Array actions = xr_action_set->get_actions();
288
for (int j = 0; j < actions.size(); j++) {
289
Ref<OpenXRAction> xr_action = actions[j];
290
291
PackedStringArray toplevel_paths = xr_action->get_toplevel_paths();
292
Vector<Tracker *> trackers_for_action;
293
294
for (int k = 0; k < toplevel_paths.size(); k++) {
295
// Only check for our tracker if our path is supported.
296
if (openxr_api->is_top_level_path_supported(toplevel_paths[k])) {
297
Tracker *tracker = find_tracker(toplevel_paths[k], true);
298
if (tracker) {
299
trackers_for_action.push_back(tracker);
300
}
301
}
302
}
303
304
// Only add our action if we have at least one valid toplevel path
305
if (trackers_for_action.size() > 0) {
306
Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers_for_action);
307
if (action) {
308
// add this to our map for creating our interaction profiles
309
xr_actions[xr_action] = action;
310
}
311
}
312
}
313
}
314
315
// now do our suggestions
316
Array interaction_profile_array = action_map->get_interaction_profiles();
317
for (int i = 0; i < interaction_profile_array.size(); i++) {
318
Ref<OpenXRInteractionProfile> xr_interaction_profile = interaction_profile_array[i];
319
320
// Note, we can only have one entry per interaction profile so if it already exists we clear it out
321
RID ip = openxr_api->interaction_profile_create(xr_interaction_profile->get_interaction_profile_path());
322
if (ip.is_valid()) {
323
openxr_api->interaction_profile_clear_bindings(ip);
324
325
for (Ref<OpenXRBindingModifier> xr_binding_modifier : xr_interaction_profile->get_binding_modifiers()) {
326
PackedByteArray bm = xr_binding_modifier->get_ip_modification();
327
if (!bm.is_empty()) {
328
openxr_api->interaction_profile_add_modifier(ip, bm);
329
}
330
}
331
332
Array xr_bindings = xr_interaction_profile->get_bindings();
333
for (int j = 0; j < xr_bindings.size(); j++) {
334
Ref<OpenXRIPBinding> xr_binding = xr_bindings[j];
335
Ref<OpenXRAction> xr_action = xr_binding->get_action();
336
337
Action *action = nullptr;
338
if (xr_actions.has(xr_action)) {
339
action = xr_actions[xr_action];
340
} else {
341
print_line("Action ", xr_action->get_name(), " isn't part of an action set!");
342
continue;
343
}
344
345
int binding_no = openxr_api->interaction_profile_add_binding(ip, action->action_rid, xr_binding->get_binding_path());
346
if (binding_no >= 0) {
347
for (Ref<OpenXRBindingModifier> xr_binding_modifier : xr_binding->get_binding_modifiers()) {
348
// Binding modifiers on bindings can be added to the interaction profile.
349
PackedByteArray bm = xr_binding_modifier->get_ip_modification();
350
if (!bm.is_empty()) {
351
openxr_api->interaction_profile_add_modifier(ip, bm);
352
}
353
354
// And possibly in the future on the binding itself, we're just preparing for that eventuality.
355
}
356
}
357
}
358
359
// Now submit our suggestions
360
openxr_api->interaction_profile_suggest_bindings(ip);
361
362
// And record it in our array so we can clean it up later on
363
if (interaction_profile_array.has(ip)) {
364
interaction_profile_array.push_back(ip);
365
}
366
}
367
}
368
}
369
}
370
371
OpenXRInterface::ActionSet *OpenXRInterface::create_action_set(const String &p_action_set_name, const String &p_localized_name, const int p_priority) {
372
ERR_FAIL_NULL_V(openxr_api, nullptr);
373
374
// find if it already exists
375
for (int i = 0; i < action_sets.size(); i++) {
376
if (action_sets[i]->action_set_name == p_action_set_name) {
377
// already exists in this set
378
return nullptr;
379
}
380
}
381
382
ActionSet *action_set = memnew(ActionSet);
383
action_set->action_set_name = p_action_set_name;
384
action_set->is_active = true;
385
action_set->action_set_rid = openxr_api->action_set_create(p_action_set_name, p_localized_name, p_priority);
386
action_sets.push_back(action_set);
387
388
return action_set;
389
}
390
391
void OpenXRInterface::free_action_sets() {
392
ERR_FAIL_NULL(openxr_api);
393
394
for (int i = 0; i < action_sets.size(); i++) {
395
ActionSet *action_set = action_sets[i];
396
397
free_actions(action_set);
398
399
openxr_api->action_set_free(action_set->action_set_rid);
400
401
memfree(action_set);
402
}
403
action_sets.clear();
404
}
405
406
OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set, const String &p_action_name, const String &p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<Tracker *> p_trackers) {
407
ERR_FAIL_NULL_V(openxr_api, nullptr);
408
409
for (int i = 0; i < p_action_set->actions.size(); i++) {
410
if (p_action_set->actions[i]->action_name == p_action_name) {
411
// already exists in this set
412
return nullptr;
413
}
414
}
415
416
Vector<RID> tracker_rids;
417
for (int i = 0; i < p_trackers.size(); i++) {
418
tracker_rids.push_back(p_trackers[i]->tracker_rid);
419
}
420
421
Action *action = memnew(Action);
422
if (p_action_type == OpenXRAction::OPENXR_ACTION_POSE) {
423
// We can't have dual action names in OpenXR hence we added _pose,
424
// but default, aim and grip and default pose action names in Godot so rename them on the tracker.
425
// NOTE need to decide on whether we should keep the naming convention or rename it on Godots side
426
if (p_action_name == "default_pose") {
427
action->action_name = "default";
428
} else if (p_action_name == "aim_pose") {
429
action->action_name = "aim";
430
} else if (p_action_name == "grip_pose") {
431
action->action_name = "grip";
432
} else {
433
action->action_name = p_action_name;
434
}
435
} else {
436
action->action_name = p_action_name;
437
}
438
439
action->action_type = p_action_type;
440
action->action_rid = openxr_api->action_create(p_action_set->action_set_rid, p_action_name, p_localized_name, p_action_type, tracker_rids);
441
p_action_set->actions.push_back(action);
442
443
// we link our actions back to our trackers so we know which actions to check when we're processing our trackers
444
for (int i = 0; i < p_trackers.size(); i++) {
445
if (!p_trackers[i]->actions.has(action)) {
446
p_trackers[i]->actions.push_back(action);
447
}
448
}
449
450
return action;
451
}
452
453
OpenXRInterface::Action *OpenXRInterface::find_action(const String &p_action_name) {
454
// We just find the first action by this name
455
456
for (int i = 0; i < action_sets.size(); i++) {
457
for (int j = 0; j < action_sets[i]->actions.size(); j++) {
458
if (action_sets[i]->actions[j]->action_name == p_action_name) {
459
return action_sets[i]->actions[j];
460
}
461
}
462
}
463
464
// not found
465
return nullptr;
466
}
467
468
void OpenXRInterface::free_actions(ActionSet *p_action_set) {
469
ERR_FAIL_NULL(openxr_api);
470
471
for (int i = 0; i < p_action_set->actions.size(); i++) {
472
Action *action = p_action_set->actions[i];
473
474
openxr_api->action_free(action->action_rid);
475
476
memdelete(action);
477
}
478
p_action_set->actions.clear();
479
}
480
481
OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_tracker_name, bool p_create) {
482
XRServer *xr_server = XRServer::get_singleton();
483
ERR_FAIL_NULL_V(xr_server, nullptr);
484
ERR_FAIL_NULL_V(openxr_api, nullptr);
485
486
Tracker *tracker = nullptr;
487
for (int i = 0; i < trackers.size(); i++) {
488
tracker = trackers[i];
489
if (tracker->tracker_name == p_tracker_name) {
490
return tracker;
491
}
492
}
493
494
if (!p_create) {
495
return nullptr;
496
}
497
498
ERR_FAIL_COND_V(!openxr_api->is_top_level_path_supported(p_tracker_name), nullptr);
499
500
// Create our RID
501
RID tracker_rid = openxr_api->tracker_create(p_tracker_name);
502
ERR_FAIL_COND_V(tracker_rid.is_null(), nullptr);
503
504
// Create our controller tracker.
505
Ref<XRControllerTracker> controller_tracker;
506
controller_tracker.instantiate();
507
508
// We have standardized some names to make things nicer to the user so lets recognize the toplevel paths related to these.
509
if (p_tracker_name == "/user/hand/left") {
510
controller_tracker->set_tracker_name("left_hand");
511
controller_tracker->set_tracker_desc("Left hand controller");
512
controller_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT);
513
} else if (p_tracker_name == "/user/hand/right") {
514
controller_tracker->set_tracker_name("right_hand");
515
controller_tracker->set_tracker_desc("Right hand controller");
516
controller_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT);
517
} else {
518
controller_tracker->set_tracker_name(p_tracker_name);
519
controller_tracker->set_tracker_desc(p_tracker_name);
520
}
521
controller_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE);
522
xr_server->add_tracker(controller_tracker);
523
524
// create a new entry
525
tracker = memnew(Tracker);
526
tracker->tracker_name = p_tracker_name;
527
tracker->tracker_rid = tracker_rid;
528
tracker->controller_tracker = controller_tracker;
529
tracker->interaction_profile = RID();
530
trackers.push_back(tracker);
531
532
return tracker;
533
}
534
535
void OpenXRInterface::tracker_profile_changed(RID p_tracker, RID p_interaction_profile) {
536
Tracker *tracker = nullptr;
537
for (int i = 0; i < trackers.size() && tracker == nullptr; i++) {
538
if (trackers[i]->tracker_rid == p_tracker) {
539
tracker = trackers[i];
540
}
541
}
542
ERR_FAIL_NULL(tracker);
543
544
tracker->interaction_profile = p_interaction_profile;
545
546
if (p_interaction_profile.is_null()) {
547
print_verbose("OpenXR: Interaction profile for " + tracker->tracker_name + " changed to " + INTERACTION_PROFILE_NONE);
548
tracker->controller_tracker->set_tracker_profile(INTERACTION_PROFILE_NONE);
549
} else {
550
String name = openxr_api->interaction_profile_get_name(p_interaction_profile);
551
print_verbose("OpenXR: Interaction profile for " + tracker->tracker_name + " changed to " + name);
552
tracker->controller_tracker->set_tracker_profile(name);
553
}
554
}
555
556
void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
557
ERR_FAIL_NULL(openxr_api);
558
ERR_FAIL_COND(p_tracker->controller_tracker.is_null());
559
560
// Note, which actions are actually bound to inputs are handled by our interaction profiles however interaction
561
// profiles are suggested bindings for controller types we know about. OpenXR runtimes can stray away from these
562
// and rebind them or even offer bindings to controllers that are not known to us.
563
564
// We don't really have a consistent way to detect whether a controller is active however as long as it is
565
// unbound it seems to be unavailable, so far unknown controller seem to mimic one of the profiles we've
566
// supplied.
567
if (p_tracker->interaction_profile.is_null()) {
568
return;
569
}
570
571
// We check all actions that are related to our tracker.
572
for (int i = 0; i < p_tracker->actions.size(); i++) {
573
Action *action = p_tracker->actions[i];
574
switch (action->action_type) {
575
case OpenXRAction::OPENXR_ACTION_BOOL: {
576
bool pressed = openxr_api->get_action_bool(action->action_rid, p_tracker->tracker_rid);
577
p_tracker->controller_tracker->set_input(action->action_name, Variant(pressed));
578
} break;
579
case OpenXRAction::OPENXR_ACTION_FLOAT: {
580
real_t value = openxr_api->get_action_float(action->action_rid, p_tracker->tracker_rid);
581
p_tracker->controller_tracker->set_input(action->action_name, Variant(value));
582
} break;
583
case OpenXRAction::OPENXR_ACTION_VECTOR2: {
584
Vector2 value = openxr_api->get_action_vector2(action->action_rid, p_tracker->tracker_rid);
585
p_tracker->controller_tracker->set_input(action->action_name, Variant(value));
586
} break;
587
case OpenXRAction::OPENXR_ACTION_POSE: {
588
Transform3D transform;
589
Vector3 linear, angular;
590
591
XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(action->action_rid, p_tracker->tracker_rid, transform, linear, angular);
592
593
if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) {
594
p_tracker->controller_tracker->set_pose(action->action_name, transform, linear, angular, confidence);
595
} else {
596
p_tracker->controller_tracker->invalidate_pose(action->action_name);
597
}
598
} break;
599
default: {
600
// not yet supported
601
} break;
602
}
603
}
604
}
605
606
void OpenXRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
607
ERR_FAIL_NULL(openxr_api);
608
609
Action *action = find_action(p_action_name);
610
ERR_FAIL_NULL(action);
611
612
// We need to map our tracker name to our OpenXR name for our inbuild names.
613
String tracker_name = p_tracker_name;
614
if (tracker_name == "left_hand") {
615
tracker_name = "/user/hand/left";
616
} else if (tracker_name == "right_hand") {
617
tracker_name = "/user/hand/right";
618
}
619
Tracker *tracker = find_tracker(tracker_name);
620
ERR_FAIL_NULL(tracker);
621
622
// TODO OpenXR does not support delay, so we may need to add support for that somehow...
623
624
XrDuration duration = XrDuration(p_duration_sec * 1000000000.0); // seconds -> nanoseconds
625
626
openxr_api->trigger_haptic_pulse(action->action_rid, tracker->tracker_rid, p_frequency, p_amplitude, duration);
627
}
628
629
void OpenXRInterface::free_trackers() {
630
XRServer *xr_server = XRServer::get_singleton();
631
ERR_FAIL_NULL(xr_server);
632
ERR_FAIL_NULL(openxr_api);
633
634
for (int i = 0; i < trackers.size(); i++) {
635
Tracker *tracker = trackers[i];
636
637
openxr_api->tracker_free(tracker->tracker_rid);
638
xr_server->remove_tracker(tracker->controller_tracker);
639
tracker->controller_tracker.unref();
640
641
memdelete(tracker);
642
}
643
trackers.clear();
644
}
645
646
void OpenXRInterface::free_interaction_profiles() {
647
ERR_FAIL_NULL(openxr_api);
648
649
for (const RID &interaction_profile : interaction_profiles) {
650
openxr_api->interaction_profile_free(interaction_profile);
651
}
652
interaction_profiles.clear();
653
}
654
655
bool OpenXRInterface::initialize_on_startup() const {
656
if (openxr_api == nullptr) {
657
return false;
658
} else if (!openxr_api->is_initialized()) {
659
return false;
660
} else {
661
return true;
662
}
663
}
664
665
bool OpenXRInterface::is_initialized() const {
666
return initialized;
667
}
668
669
bool OpenXRInterface::initialize() {
670
XRServer *xr_server = XRServer::get_singleton();
671
ERR_FAIL_NULL_V(xr_server, false);
672
673
if (openxr_api == nullptr) {
674
return false;
675
} else if (!openxr_api->is_initialized()) {
676
return false;
677
} else if (initialized) {
678
return true;
679
}
680
681
// load up our action sets before setting up our session, note that our profiles are suggestions, OpenXR takes ownership of (re)binding
682
_load_action_map();
683
684
if (!openxr_api->initialize_session()) {
685
return false;
686
}
687
688
// we must create a tracker for our head
689
head.instantiate();
690
head->set_tracker_type(XRServer::TRACKER_HEAD);
691
head->set_tracker_name("head");
692
head->set_tracker_desc("Players head");
693
xr_server->add_tracker(head);
694
695
// attach action sets
696
Vector<RID> loaded_action_sets;
697
for (int i = 0; i < action_sets.size(); i++) {
698
loaded_action_sets.append(action_sets[i]->action_set_rid);
699
}
700
openxr_api->attach_action_sets(loaded_action_sets);
701
702
// make this our primary interface
703
xr_server->set_primary_interface(this);
704
705
// Register an additional output with the display server, so rendering won't
706
// be skipped if no windows are visible.
707
DisplayServer::get_singleton()->register_additional_output(this);
708
709
initialized = true;
710
711
return initialized;
712
}
713
714
void OpenXRInterface::uninitialize() {
715
// Our OpenXR driver will clean itself up properly when Godot exits, so we just do some basic stuff here
716
717
// end the session if we need to?
718
719
// cleanup stuff
720
free_trackers();
721
free_interaction_profiles();
722
free_action_sets();
723
724
XRServer *xr_server = XRServer::get_singleton();
725
if (xr_server) {
726
if (head.is_valid()) {
727
xr_server->remove_tracker(head);
728
head.unref();
729
}
730
}
731
732
DisplayServer::get_singleton()->unregister_additional_output(this);
733
734
initialized = false;
735
}
736
737
Dictionary OpenXRInterface::get_system_info() {
738
Dictionary dict;
739
740
if (openxr_api) {
741
dict[SNAME("XRRuntimeName")] = openxr_api->get_runtime_name();
742
dict[SNAME("XRRuntimeVersion")] = openxr_api->get_runtime_version();
743
dict[SNAME("OpenXRSystemName")] = openxr_api->get_system_name();
744
dict[SNAME("OpenXRVendorID")] = openxr_api->get_vendor_id();
745
}
746
747
return dict;
748
}
749
750
bool OpenXRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
751
if (p_mode == XRInterface::XR_PLAY_AREA_3DOF) {
752
return false;
753
}
754
return true;
755
}
756
757
XRInterface::PlayAreaMode OpenXRInterface::get_play_area_mode() const {
758
if (!openxr_api || !initialized) {
759
return XRInterface::XR_PLAY_AREA_UNKNOWN;
760
}
761
762
XrReferenceSpaceType reference_space = openxr_api->get_reference_space();
763
764
if (reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL) {
765
return XRInterface::XR_PLAY_AREA_SITTING;
766
} else if (reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT) {
767
return XRInterface::XR_PLAY_AREA_ROOMSCALE;
768
} else if (reference_space == XR_REFERENCE_SPACE_TYPE_STAGE) {
769
return XRInterface::XR_PLAY_AREA_STAGE;
770
} else if (reference_space == XR_REFERENCE_SPACE_TYPE_MAX_ENUM) {
771
return XRInterface::XR_PLAY_AREA_CUSTOM;
772
}
773
774
return XRInterface::XR_PLAY_AREA_UNKNOWN;
775
}
776
777
bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
778
ERR_FAIL_NULL_V(openxr_api, false);
779
780
XrReferenceSpaceType reference_space;
781
782
if (p_mode == XRInterface::XR_PLAY_AREA_SITTING) {
783
reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
784
} else if (p_mode == XRInterface::XR_PLAY_AREA_ROOMSCALE) {
785
reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
786
} else if (p_mode == XRInterface::XR_PLAY_AREA_STAGE) {
787
reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
788
} else {
789
return false;
790
}
791
792
if (openxr_api->set_requested_reference_space(reference_space)) {
793
XRServer *xr_server = XRServer::get_singleton();
794
if (xr_server) {
795
xr_server->clear_reference_frame();
796
}
797
return true;
798
}
799
800
return false;
801
}
802
803
PackedVector3Array OpenXRInterface::get_play_area() const {
804
XRServer *xr_server = XRServer::get_singleton();
805
ERR_FAIL_NULL_V(xr_server, PackedVector3Array());
806
PackedVector3Array arr;
807
808
Vector3 sides[4] = {
809
Vector3(-0.5f, 0.0f, -0.5f),
810
Vector3(0.5f, 0.0f, -0.5f),
811
Vector3(0.5f, 0.0f, 0.5f),
812
Vector3(-0.5f, 0.0f, 0.5f),
813
};
814
815
if (openxr_api != nullptr && openxr_api->is_initialized()) {
816
Size2 extents = openxr_api->get_play_space_bounds();
817
if (extents.width != 0.0 && extents.height != 0.0) {
818
Transform3D reference_frame = xr_server->get_reference_frame();
819
820
for (int i = 0; i < 4; i++) {
821
Vector3 coord = sides[i];
822
823
// Scale it up.
824
coord.x *= extents.width;
825
coord.z *= extents.height;
826
827
// Now apply our reference.
828
Vector3 out = reference_frame.xform(coord);
829
arr.push_back(out);
830
}
831
} else {
832
WARN_PRINT_ONCE("OpenXR: No extents available.");
833
}
834
}
835
836
return arr;
837
}
838
839
float OpenXRInterface::get_display_refresh_rate() const {
840
if (openxr_api == nullptr) {
841
return 0.0;
842
} else if (!openxr_api->is_initialized()) {
843
return 0.0;
844
} else {
845
return openxr_api->get_display_refresh_rate();
846
}
847
}
848
849
void OpenXRInterface::set_display_refresh_rate(float p_refresh_rate) {
850
if (openxr_api == nullptr) {
851
return;
852
} else if (!openxr_api->is_initialized()) {
853
return;
854
} else {
855
openxr_api->set_display_refresh_rate(p_refresh_rate);
856
}
857
}
858
859
Array OpenXRInterface::get_available_display_refresh_rates() const {
860
if (openxr_api == nullptr) {
861
return Array();
862
} else if (!openxr_api->is_initialized()) {
863
return Array();
864
} else {
865
return openxr_api->get_available_display_refresh_rates();
866
}
867
}
868
869
bool OpenXRInterface::is_hand_tracking_supported() {
870
if (openxr_api == nullptr) {
871
return false;
872
} else if (!openxr_api->is_initialized()) {
873
return false;
874
} else {
875
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
876
if (hand_tracking_ext == nullptr) {
877
return false;
878
} else {
879
return hand_tracking_ext->get_active();
880
}
881
}
882
}
883
884
bool OpenXRInterface::is_hand_interaction_supported() const {
885
if (openxr_api == nullptr) {
886
return false;
887
} else if (!openxr_api->is_initialized()) {
888
return false;
889
} else {
890
OpenXRHandInteractionExtension *hand_interaction_ext = OpenXRHandInteractionExtension::get_singleton();
891
if (hand_interaction_ext == nullptr) {
892
return false;
893
} else {
894
return hand_interaction_ext->is_available();
895
}
896
}
897
}
898
899
bool OpenXRInterface::is_eye_gaze_interaction_supported() {
900
if (openxr_api == nullptr) {
901
return false;
902
} else if (!openxr_api->is_initialized()) {
903
return false;
904
} else {
905
OpenXREyeGazeInteractionExtension *eye_gaze_ext = OpenXREyeGazeInteractionExtension::get_singleton();
906
if (eye_gaze_ext == nullptr) {
907
return false;
908
} else {
909
return eye_gaze_ext->supports_eye_gaze_interaction();
910
}
911
}
912
}
913
914
bool OpenXRInterface::is_action_set_active(const String &p_action_set) const {
915
for (ActionSet *action_set : action_sets) {
916
if (action_set->action_set_name == p_action_set) {
917
return action_set->is_active;
918
}
919
}
920
921
WARN_PRINT("OpenXR: Unknown action set " + p_action_set);
922
return false;
923
}
924
925
void OpenXRInterface::set_action_set_active(const String &p_action_set, bool p_active) {
926
for (ActionSet *action_set : action_sets) {
927
if (action_set->action_set_name == p_action_set) {
928
action_set->is_active = p_active;
929
return;
930
}
931
}
932
933
WARN_PRINT("OpenXR: Unknown action set " + p_action_set);
934
}
935
936
Array OpenXRInterface::get_action_sets() const {
937
Array arr;
938
939
for (ActionSet *action_set : action_sets) {
940
arr.push_back(action_set->action_set_name);
941
}
942
943
return arr;
944
}
945
946
float OpenXRInterface::get_vrs_min_radius() const {
947
return xr_vrs.get_vrs_min_radius();
948
}
949
950
void OpenXRInterface::set_vrs_min_radius(float p_vrs_min_radius) {
951
xr_vrs.set_vrs_min_radius(p_vrs_min_radius);
952
}
953
954
float OpenXRInterface::get_vrs_strength() const {
955
return xr_vrs.get_vrs_strength();
956
}
957
958
void OpenXRInterface::set_vrs_strength(float p_vrs_strength) {
959
xr_vrs.set_vrs_strength(p_vrs_strength);
960
}
961
962
double OpenXRInterface::get_render_target_size_multiplier() const {
963
if (openxr_api == nullptr) {
964
return 1.0;
965
} else {
966
return openxr_api->get_render_target_size_multiplier();
967
}
968
}
969
970
void OpenXRInterface::set_render_target_size_multiplier(double multiplier) {
971
if (openxr_api == nullptr) {
972
return;
973
} else {
974
openxr_api->set_render_target_size_multiplier(multiplier);
975
}
976
}
977
978
bool OpenXRInterface::is_foveation_supported() const {
979
if (openxr_api == nullptr) {
980
return false;
981
} else {
982
return openxr_api->is_foveation_supported();
983
}
984
}
985
986
int OpenXRInterface::get_foveation_level() const {
987
if (openxr_api == nullptr) {
988
return 0;
989
} else {
990
return openxr_api->get_foveation_level();
991
}
992
}
993
994
void OpenXRInterface::set_foveation_level(int p_foveation_level) {
995
if (openxr_api == nullptr) {
996
return;
997
} else {
998
openxr_api->set_foveation_level(p_foveation_level);
999
}
1000
}
1001
1002
bool OpenXRInterface::get_foveation_dynamic() const {
1003
if (openxr_api == nullptr) {
1004
return false;
1005
} else {
1006
return openxr_api->get_foveation_dynamic();
1007
}
1008
}
1009
1010
void OpenXRInterface::set_foveation_dynamic(bool p_foveation_dynamic) {
1011
if (openxr_api == nullptr) {
1012
return;
1013
} else {
1014
openxr_api->set_foveation_dynamic(p_foveation_dynamic);
1015
}
1016
}
1017
1018
Size2 OpenXRInterface::get_render_target_size() {
1019
if (openxr_api == nullptr) {
1020
return Size2();
1021
} else {
1022
return openxr_api->get_recommended_target_size();
1023
}
1024
}
1025
1026
uint32_t OpenXRInterface::get_view_count() {
1027
// TODO set this based on our configuration
1028
return 2;
1029
}
1030
1031
void OpenXRInterface::_set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye) {
1032
p_transform = Transform3D();
1033
1034
// if we're not tracking, don't put our head on the floor...
1035
p_transform.origin.y = 1.5 * p_world_scale;
1036
1037
// overkill but..
1038
if (p_eye == 1) {
1039
p_transform.origin.x = 0.03 * p_world_scale;
1040
} else if (p_eye == 2) {
1041
p_transform.origin.x = -0.03 * p_world_scale;
1042
}
1043
}
1044
1045
Transform3D OpenXRInterface::get_camera_transform() {
1046
XRServer *xr_server = XRServer::get_singleton();
1047
ERR_FAIL_NULL_V(xr_server, Transform3D());
1048
1049
Transform3D hmd_transform;
1050
double world_scale = xr_server->get_world_scale();
1051
1052
// head_transform should be updated in process
1053
1054
hmd_transform.basis = head_transform.basis;
1055
hmd_transform.origin = head_transform.origin * world_scale;
1056
1057
return hmd_transform;
1058
}
1059
1060
Transform3D OpenXRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
1061
XRServer *xr_server = XRServer::get_singleton();
1062
ERR_FAIL_NULL_V(xr_server, Transform3D());
1063
ERR_FAIL_UNSIGNED_INDEX_V_MSG(p_view, get_view_count(), Transform3D(), "View index outside bounds.");
1064
1065
Transform3D t;
1066
if (openxr_api && openxr_api->get_view_transform(p_view, t)) {
1067
// update our cached value if we have a valid transform
1068
transform_for_view[p_view] = t;
1069
} else {
1070
// reuse cached value
1071
t = transform_for_view[p_view];
1072
}
1073
1074
// Apply our world scale
1075
double world_scale = xr_server->get_world_scale();
1076
t.origin *= world_scale;
1077
1078
return p_cam_transform * xr_server->get_reference_frame() * t;
1079
}
1080
1081
Projection OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) {
1082
Projection cm;
1083
ERR_FAIL_UNSIGNED_INDEX_V_MSG(p_view, get_view_count(), cm, "View index outside bounds.");
1084
1085
if (openxr_api) {
1086
if (openxr_api->get_view_projection(p_view, p_z_near, p_z_far, cm)) {
1087
return cm;
1088
}
1089
}
1090
1091
// Failed to get from our OpenXR device? Default to some sort of sensible camera matrix..
1092
cm.set_for_hmd(p_view + 1, 1.0, 6.0, 14.5, 4.0, 1.5, p_z_near, p_z_far);
1093
1094
return cm;
1095
}
1096
1097
Rect2i OpenXRInterface::get_render_region() {
1098
if (openxr_api) {
1099
return openxr_api->get_render_region();
1100
} else {
1101
return Rect2i();
1102
}
1103
}
1104
1105
RID OpenXRInterface::get_color_texture() {
1106
if (openxr_api) {
1107
return openxr_api->get_color_texture();
1108
} else {
1109
return RID();
1110
}
1111
}
1112
1113
RID OpenXRInterface::get_depth_texture() {
1114
if (openxr_api) {
1115
return openxr_api->get_depth_texture();
1116
} else {
1117
return RID();
1118
}
1119
}
1120
1121
RID OpenXRInterface::get_velocity_texture() {
1122
if (openxr_api) {
1123
return openxr_api->get_velocity_texture();
1124
} else {
1125
return RID();
1126
}
1127
}
1128
1129
RID OpenXRInterface::get_velocity_depth_texture() {
1130
if (openxr_api) {
1131
return openxr_api->get_velocity_depth_texture();
1132
} else {
1133
return RID();
1134
}
1135
}
1136
1137
Size2i OpenXRInterface::get_velocity_target_size() {
1138
if (openxr_api) {
1139
return openxr_api->get_velocity_target_size();
1140
} else {
1141
return Size2i();
1142
}
1143
}
1144
1145
void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrackingExtension::HandTrackedHands p_hand) {
1146
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1147
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1148
OpenXRInterface::Tracker *tracker = find_tracker(p_path);
1149
if (tracker && tracker->controller_tracker.is_valid()) {
1150
XrSpaceLocationFlags location_flags = hand_tracking_ext->get_hand_joint_location_flags(p_hand, XR_HAND_JOINT_PALM_EXT);
1151
1152
if (location_flags & (XR_SPACE_LOCATION_ORIENTATION_VALID_BIT + XR_SPACE_LOCATION_POSITION_VALID_BIT)) {
1153
static const XrSpaceLocationFlags all_location_flags = XR_SPACE_LOCATION_ORIENTATION_VALID_BIT + XR_SPACE_LOCATION_POSITION_VALID_BIT + XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT + XR_SPACE_LOCATION_POSITION_TRACKED_BIT;
1154
XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW;
1155
Transform3D transform;
1156
Vector3 linear_velocity;
1157
Vector3 angular_velocity;
1158
1159
if ((location_flags & all_location_flags) == all_location_flags) {
1160
// All flags set? confidence is high!
1161
confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH;
1162
}
1163
1164
if (location_flags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
1165
transform.basis = Basis(hand_tracking_ext->get_hand_joint_rotation(p_hand, XR_HAND_JOINT_PALM_EXT));
1166
}
1167
if (location_flags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
1168
transform.origin = hand_tracking_ext->get_hand_joint_position(p_hand, XR_HAND_JOINT_PALM_EXT);
1169
}
1170
1171
XrSpaceVelocityFlags velocity_flags = hand_tracking_ext->get_hand_joint_location_flags(p_hand, XR_HAND_JOINT_PALM_EXT);
1172
if (velocity_flags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
1173
linear_velocity = hand_tracking_ext->get_hand_joint_linear_velocity(p_hand, XR_HAND_JOINT_PALM_EXT);
1174
}
1175
if (velocity_flags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
1176
angular_velocity = hand_tracking_ext->get_hand_joint_angular_velocity(p_hand, XR_HAND_JOINT_PALM_EXT);
1177
}
1178
1179
tracker->controller_tracker->set_pose("skeleton", transform, linear_velocity, angular_velocity, confidence);
1180
} else {
1181
tracker->controller_tracker->invalidate_pose("skeleton");
1182
}
1183
}
1184
}
1185
}
1186
1187
void OpenXRInterface::process() {
1188
if (openxr_api) {
1189
// do our normal process
1190
if (openxr_api->process()) {
1191
Transform3D t;
1192
Vector3 linear_velocity;
1193
Vector3 angular_velocity;
1194
head_confidence = openxr_api->get_head_center(t, linear_velocity, angular_velocity);
1195
if (head_confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) {
1196
// Only update our transform if we have one to update it with
1197
// note that poses are stored without world scale and reference frame applied!
1198
head_transform = t;
1199
head_linear_velocity = linear_velocity;
1200
head_angular_velocity = angular_velocity;
1201
}
1202
}
1203
1204
// handle our action sets....
1205
Vector<RID> active_sets;
1206
for (int i = 0; i < action_sets.size(); i++) {
1207
if (action_sets[i]->is_active) {
1208
active_sets.push_back(action_sets[i]->action_set_rid);
1209
}
1210
}
1211
1212
if (openxr_api->sync_action_sets(active_sets)) {
1213
for (int i = 0; i < trackers.size(); i++) {
1214
handle_tracker(trackers[i]);
1215
}
1216
}
1217
1218
// Handle hand tracking
1219
handle_hand_tracking("/user/hand/left", OpenXRHandTrackingExtension::OPENXR_TRACKED_LEFT_HAND);
1220
handle_hand_tracking("/user/hand/right", OpenXRHandTrackingExtension::OPENXR_TRACKED_RIGHT_HAND);
1221
}
1222
1223
if (head.is_valid()) {
1224
head->set_pose("default", head_transform, head_linear_velocity, head_angular_velocity, head_confidence);
1225
}
1226
1227
if (reference_stage_changing) {
1228
// Now that we have updated tracking information in our updated reference space, trigger our pose recentered signal.
1229
emit_signal(SNAME("pose_recentered"));
1230
reference_stage_changing = false;
1231
}
1232
}
1233
1234
void OpenXRInterface::pre_render() {
1235
if (openxr_api) {
1236
openxr_api->pre_render();
1237
}
1238
}
1239
1240
bool OpenXRInterface::pre_draw_viewport(RID p_render_target) {
1241
if (openxr_api) {
1242
return openxr_api->pre_draw_viewport(p_render_target);
1243
} else {
1244
// don't render
1245
return false;
1246
}
1247
}
1248
1249
Vector<BlitToScreen> OpenXRInterface::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) {
1250
Vector<BlitToScreen> blit_to_screen;
1251
1252
#ifndef ANDROID_ENABLED
1253
// If separate HMD we should output one eye to screen
1254
if (p_screen_rect != Rect2()) {
1255
BlitToScreen blit;
1256
1257
blit.render_target = p_render_target;
1258
blit.multi_view.use_layer = true;
1259
blit.multi_view.layer = 0;
1260
blit.lens_distortion.apply = false;
1261
1262
Size2 render_size = get_render_target_size();
1263
Rect2 dst_rect = p_screen_rect;
1264
float new_height = dst_rect.size.x * (render_size.y / render_size.x);
1265
if (new_height > dst_rect.size.y) {
1266
dst_rect.position.y = (0.5 * dst_rect.size.y) - (0.5 * new_height);
1267
dst_rect.size.y = new_height;
1268
} else {
1269
float new_width = dst_rect.size.y * (render_size.x / render_size.y);
1270
1271
dst_rect.position.x = (0.5 * dst_rect.size.x) - (0.5 * new_width);
1272
dst_rect.size.x = new_width;
1273
}
1274
1275
blit.dst_rect = dst_rect;
1276
blit_to_screen.push_back(blit);
1277
}
1278
#endif
1279
1280
if (openxr_api) {
1281
openxr_api->post_draw_viewport(p_render_target);
1282
}
1283
1284
return blit_to_screen;
1285
}
1286
1287
void OpenXRInterface::end_frame() {
1288
if (openxr_api) {
1289
openxr_api->end_frame();
1290
}
1291
}
1292
1293
bool OpenXRInterface::is_passthrough_supported() {
1294
return get_supported_environment_blend_modes().find(XR_ENV_BLEND_MODE_ALPHA_BLEND);
1295
}
1296
1297
bool OpenXRInterface::is_passthrough_enabled() {
1298
return get_environment_blend_mode() == XR_ENV_BLEND_MODE_ALPHA_BLEND;
1299
}
1300
1301
bool OpenXRInterface::start_passthrough() {
1302
return set_environment_blend_mode(XR_ENV_BLEND_MODE_ALPHA_BLEND);
1303
}
1304
1305
void OpenXRInterface::stop_passthrough() {
1306
set_environment_blend_mode(XR_ENV_BLEND_MODE_OPAQUE);
1307
}
1308
1309
Array OpenXRInterface::get_supported_environment_blend_modes() {
1310
Array modes;
1311
1312
if (!openxr_api) {
1313
return modes;
1314
}
1315
1316
const Vector<XrEnvironmentBlendMode> env_blend_modes = openxr_api->get_supported_environment_blend_modes();
1317
1318
for (const XrEnvironmentBlendMode &env_blend_mode : env_blend_modes) {
1319
switch (env_blend_mode) {
1320
case XR_ENVIRONMENT_BLEND_MODE_OPAQUE:
1321
modes.push_back(XR_ENV_BLEND_MODE_OPAQUE);
1322
break;
1323
case XR_ENVIRONMENT_BLEND_MODE_ADDITIVE:
1324
modes.push_back(XR_ENV_BLEND_MODE_ADDITIVE);
1325
break;
1326
case XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND:
1327
modes.push_back(XR_ENV_BLEND_MODE_ALPHA_BLEND);
1328
break;
1329
default:
1330
WARN_PRINT(vformat("Unsupported blend mode found: %s.", String::num_int64(int64_t(env_blend_mode))));
1331
}
1332
}
1333
1334
if (openxr_api->is_environment_blend_mode_alpha_blend_supported() == OpenXRAPI::OPENXR_ALPHA_BLEND_MODE_SUPPORT_EMULATING) {
1335
modes.push_back(XR_ENV_BLEND_MODE_ALPHA_BLEND);
1336
}
1337
1338
return modes;
1339
}
1340
1341
XRInterface::EnvironmentBlendMode OpenXRInterface::get_environment_blend_mode() const {
1342
if (openxr_api) {
1343
XrEnvironmentBlendMode oxr_blend_mode = openxr_api->get_environment_blend_mode();
1344
switch (oxr_blend_mode) {
1345
case XR_ENVIRONMENT_BLEND_MODE_OPAQUE: {
1346
return XR_ENV_BLEND_MODE_OPAQUE;
1347
} break;
1348
case XR_ENVIRONMENT_BLEND_MODE_ADDITIVE: {
1349
return XR_ENV_BLEND_MODE_ADDITIVE;
1350
} break;
1351
case XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND: {
1352
return XR_ENV_BLEND_MODE_ALPHA_BLEND;
1353
} break;
1354
default:
1355
break;
1356
}
1357
}
1358
1359
return XR_ENV_BLEND_MODE_OPAQUE;
1360
}
1361
1362
bool OpenXRInterface::set_environment_blend_mode(XRInterface::EnvironmentBlendMode mode) {
1363
if (openxr_api) {
1364
XrEnvironmentBlendMode oxr_blend_mode;
1365
switch (mode) {
1366
case XR_ENV_BLEND_MODE_OPAQUE:
1367
oxr_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
1368
break;
1369
case XR_ENV_BLEND_MODE_ADDITIVE:
1370
oxr_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE;
1371
break;
1372
case XR_ENV_BLEND_MODE_ALPHA_BLEND:
1373
oxr_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND;
1374
break;
1375
default:
1376
WARN_PRINT("Unknown blend mode requested: " + String::num_int64(int64_t(mode)));
1377
oxr_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
1378
}
1379
return openxr_api->set_environment_blend_mode(oxr_blend_mode);
1380
}
1381
return false;
1382
}
1383
1384
void OpenXRInterface::on_state_ready() {
1385
emit_signal(SNAME("session_begun"));
1386
}
1387
1388
void OpenXRInterface::on_state_visible() {
1389
emit_signal(SNAME("session_visible"));
1390
}
1391
1392
void OpenXRInterface::on_state_synchronized() {
1393
emit_signal(SNAME("session_synchronized"));
1394
}
1395
1396
void OpenXRInterface::on_state_focused() {
1397
emit_signal(SNAME("session_focussed"));
1398
}
1399
1400
void OpenXRInterface::on_state_stopping() {
1401
emit_signal(SNAME("session_stopping"));
1402
}
1403
1404
void OpenXRInterface::on_state_loss_pending() {
1405
emit_signal(SNAME("session_loss_pending"));
1406
}
1407
1408
void OpenXRInterface::on_state_exiting() {
1409
emit_signal(SNAME("instance_exiting"));
1410
}
1411
1412
void OpenXRInterface::on_reference_space_change_pending() {
1413
reference_stage_changing = true;
1414
}
1415
1416
void OpenXRInterface::on_refresh_rate_changes(float p_new_rate) {
1417
emit_signal(SNAME("refresh_rate_changed"), p_new_rate);
1418
}
1419
1420
OpenXRInterface::SessionState OpenXRInterface::get_session_state() {
1421
if (openxr_api) {
1422
return (SessionState)openxr_api->get_session_state();
1423
}
1424
1425
return SESSION_STATE_UNKNOWN;
1426
}
1427
1428
/** Hand tracking. */
1429
void OpenXRInterface::set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range) {
1430
ERR_FAIL_INDEX(p_hand, HAND_MAX);
1431
ERR_FAIL_INDEX(p_motion_range, HAND_MOTION_RANGE_MAX);
1432
1433
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1434
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1435
XrHandJointsMotionRangeEXT xr_motion_range;
1436
switch (p_motion_range) {
1437
case HAND_MOTION_RANGE_UNOBSTRUCTED:
1438
xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT;
1439
break;
1440
case HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER:
1441
xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT;
1442
break;
1443
default:
1444
// Shouldn't get here, ERR_FAIL_INDEX should have caught this...
1445
xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT;
1446
break;
1447
}
1448
1449
hand_tracking_ext->set_motion_range(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), xr_motion_range);
1450
}
1451
}
1452
1453
OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_hand) const {
1454
ERR_FAIL_INDEX_V(p_hand, HAND_MAX, HAND_MOTION_RANGE_MAX);
1455
1456
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1457
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1458
XrHandJointsMotionRangeEXT xr_motion_range = hand_tracking_ext->get_motion_range(OpenXRHandTrackingExtension::HandTrackedHands(p_hand));
1459
1460
switch (xr_motion_range) {
1461
case XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT:
1462
return HAND_MOTION_RANGE_UNOBSTRUCTED;
1463
case XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT:
1464
return HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER;
1465
default:
1466
ERR_FAIL_V_MSG(HAND_MOTION_RANGE_MAX, "Unknown motion range returned by OpenXR");
1467
}
1468
}
1469
1470
return HAND_MOTION_RANGE_MAX;
1471
}
1472
1473
OpenXRInterface::HandTrackedSource OpenXRInterface::get_hand_tracking_source(const Hand p_hand) const {
1474
ERR_FAIL_INDEX_V(p_hand, HAND_MAX, HAND_TRACKED_SOURCE_UNKNOWN);
1475
1476
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1477
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1478
OpenXRHandTrackingExtension::HandTrackedSource source = hand_tracking_ext->get_hand_tracking_source(OpenXRHandTrackingExtension::HandTrackedHands(p_hand));
1479
switch (source) {
1480
case OpenXRHandTrackingExtension::OPENXR_SOURCE_UNOBSTRUCTED:
1481
return HAND_TRACKED_SOURCE_UNOBSTRUCTED;
1482
case OpenXRHandTrackingExtension::OPENXR_SOURCE_CONTROLLER:
1483
return HAND_TRACKED_SOURCE_CONTROLLER;
1484
case OpenXRHandTrackingExtension::OPENXR_SOURCE_UNKNOWN:
1485
case OpenXRHandTrackingExtension::OPENXR_SOURCE_NOT_TRACKED:
1486
return HAND_TRACKED_SOURCE_UNKNOWN;
1487
default:
1488
ERR_FAIL_V_MSG(HAND_TRACKED_SOURCE_UNKNOWN, "Unknown hand tracking source (" + String::num_int64(source) + ") returned by OpenXR");
1489
}
1490
}
1491
1492
return HAND_TRACKED_SOURCE_UNKNOWN;
1493
}
1494
1495
BitField<OpenXRInterface::HandJointFlags> OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const {
1496
BitField<OpenXRInterface::HandJointFlags> bits = HAND_JOINT_NONE;
1497
1498
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1499
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1500
XrSpaceLocationFlags location_flags = hand_tracking_ext->get_hand_joint_location_flags(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
1501
if (location_flags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
1502
bits.set_flag(HAND_JOINT_ORIENTATION_VALID);
1503
}
1504
if (location_flags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) {
1505
bits.set_flag(HAND_JOINT_ORIENTATION_TRACKED);
1506
}
1507
if (location_flags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
1508
bits.set_flag(HAND_JOINT_POSITION_VALID);
1509
}
1510
if (location_flags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) {
1511
bits.set_flag(HAND_JOINT_POSITION_TRACKED);
1512
}
1513
1514
XrSpaceVelocityFlags velocity_flags = hand_tracking_ext->get_hand_joint_velocity_flags(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
1515
if (velocity_flags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
1516
bits.set_flag(HAND_JOINT_LINEAR_VELOCITY_VALID);
1517
}
1518
if (velocity_flags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
1519
bits.set_flag(HAND_JOINT_ANGULAR_VELOCITY_VALID);
1520
}
1521
}
1522
1523
return bits;
1524
}
1525
1526
Quaternion OpenXRInterface::get_hand_joint_rotation(Hand p_hand, HandJoints p_joint) const {
1527
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1528
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1529
return hand_tracking_ext->get_hand_joint_rotation(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
1530
}
1531
1532
return Quaternion();
1533
}
1534
1535
Vector3 OpenXRInterface::get_hand_joint_position(Hand p_hand, HandJoints p_joint) const {
1536
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1537
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1538
return hand_tracking_ext->get_hand_joint_position(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
1539
}
1540
1541
return Vector3();
1542
}
1543
1544
float OpenXRInterface::get_hand_joint_radius(Hand p_hand, HandJoints p_joint) const {
1545
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1546
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1547
return hand_tracking_ext->get_hand_joint_radius(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
1548
}
1549
1550
return 0.0;
1551
}
1552
1553
Vector3 OpenXRInterface::get_hand_joint_linear_velocity(Hand p_hand, HandJoints p_joint) const {
1554
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1555
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1556
return hand_tracking_ext->get_hand_joint_linear_velocity(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
1557
}
1558
1559
return Vector3();
1560
}
1561
1562
Vector3 OpenXRInterface::get_hand_joint_angular_velocity(Hand p_hand, HandJoints p_joint) const {
1563
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
1564
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
1565
return hand_tracking_ext->get_hand_joint_angular_velocity(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
1566
}
1567
1568
return Vector3();
1569
}
1570
1571
RID OpenXRInterface::get_vrs_texture() {
1572
if (!openxr_api) {
1573
return RID();
1574
}
1575
1576
RID density_map = openxr_api->get_density_map_texture();
1577
if (density_map.is_valid()) {
1578
return density_map;
1579
}
1580
1581
PackedVector2Array eye_foci;
1582
1583
Size2 target_size = get_render_target_size();
1584
real_t aspect_ratio = target_size.x / target_size.y;
1585
uint32_t view_count = get_view_count();
1586
1587
for (uint32_t v = 0; v < view_count; v++) {
1588
eye_foci.push_back(openxr_api->get_eye_focus(v, aspect_ratio));
1589
}
1590
1591
xr_vrs.set_vrs_render_region(get_render_region());
1592
1593
return xr_vrs.make_vrs_texture(target_size, eye_foci);
1594
}
1595
1596
XRInterface::VRSTextureFormat OpenXRInterface::get_vrs_texture_format() {
1597
if (!openxr_api) {
1598
return XR_VRS_TEXTURE_FORMAT_UNIFIED;
1599
}
1600
1601
RID density_map = openxr_api->get_density_map_texture();
1602
if (density_map.is_valid()) {
1603
return XR_VRS_TEXTURE_FORMAT_FRAGMENT_DENSITY_MAP;
1604
}
1605
1606
return XR_VRS_TEXTURE_FORMAT_UNIFIED;
1607
}
1608
1609
void OpenXRInterface::set_cpu_level(PerfSettingsLevel p_level) {
1610
OpenXRPerformanceSettingsExtension *performance_settings_ext = OpenXRPerformanceSettingsExtension::get_singleton();
1611
if (performance_settings_ext && performance_settings_ext->is_available()) {
1612
performance_settings_ext->set_cpu_level(p_level);
1613
}
1614
}
1615
1616
void OpenXRInterface::set_gpu_level(PerfSettingsLevel p_level) {
1617
OpenXRPerformanceSettingsExtension *performance_settings_ext = OpenXRPerformanceSettingsExtension::get_singleton();
1618
if (performance_settings_ext && performance_settings_ext->is_available()) {
1619
performance_settings_ext->set_gpu_level(p_level);
1620
}
1621
}
1622
1623
void OpenXRInterface::on_cpu_level_changed(PerfSettingsSubDomain p_sub_domain, PerfSettingsNotificationLevel p_from_level, PerfSettingsNotificationLevel p_to_level) {
1624
emit_signal(SNAME("cpu_level_changed"), p_sub_domain, p_from_level, p_to_level);
1625
}
1626
1627
void OpenXRInterface::on_gpu_level_changed(PerfSettingsSubDomain p_sub_domain, PerfSettingsNotificationLevel p_from_level, PerfSettingsNotificationLevel p_to_level) {
1628
emit_signal(SNAME("gpu_level_changed"), p_sub_domain, p_from_level, p_to_level);
1629
}
1630
1631
OpenXRInterface::OpenXRInterface() {
1632
openxr_api = OpenXRAPI::get_singleton();
1633
if (openxr_api) {
1634
openxr_api->set_xr_interface(this);
1635
}
1636
1637
// while we don't have head tracking, don't put the headset on the floor...
1638
_set_default_pos(head_transform, 1.0, 0);
1639
_set_default_pos(transform_for_view[0], 1.0, 1);
1640
_set_default_pos(transform_for_view[1], 1.0, 2);
1641
}
1642
1643
OpenXRInterface::~OpenXRInterface() {
1644
if (is_initialized()) {
1645
uninitialize();
1646
}
1647
1648
if (openxr_api) {
1649
openxr_api->set_xr_interface(nullptr);
1650
openxr_api = nullptr;
1651
}
1652
}
1653
1654