2
0
mirror of https://github.com/godotengine/godot.git synced 2025-04-25 01:48:08 +08:00

Merge pull request from dsnopek/openxr-alternative-reference-spaces

OpenXR: Support alternative reference spaces from extensions
This commit is contained in:
Rémi Verschelde 2025-03-28 14:32:00 +01:00
commit 46a5940950
No known key found for this signature in database
GPG Key ID: C3336907360768E1
12 changed files with 239 additions and 17 deletions

@ -263,6 +263,9 @@
<constant name="XR_PLAY_AREA_STAGE" value="4" enum="PlayAreaMode">
Same as [constant XR_PLAY_AREA_ROOMSCALE] but origin point is fixed to the center of the physical space. In this mode, system-level recentering may be disabled, requiring the use of [method XRServer.center_on_hmd].
</constant>
<constant name="XR_PLAY_AREA_CUSTOM" value="2147483647" enum="PlayAreaMode">
Custom play area set by a GDExtension.
</constant>
<constant name="XR_ENV_BLEND_MODE_OPAQUE" value="0" enum="EnvironmentBlendMode">
Opaque blend mode. This is typically used for VR devices.
</constant>

@ -230,6 +230,13 @@
Registers the given extension as a composition layer provider.
</description>
</method>
<method name="register_frame_info_extension">
<return type="void" />
<param index="0" name="extension" type="OpenXRExtensionWrapper" />
<description>
Registers the given extension as modifying frame info via the [method OpenXRExtensionWrapper._set_frame_wait_info_and_get_next_pointer], [method OpenXRExtensionWrapper._set_view_locate_info_and_get_next_pointer], or [method OpenXRExtensionWrapper._set_frame_end_info_and_get_next_pointer] virtual methods.
</description>
</method>
<method name="register_projection_views_extension">
<return type="void" />
<param index="0" name="extension" type="OpenXRExtensionWrapper" />
@ -237,6 +244,13 @@
Registers the given extension as a provider of additional data structures to projections views.
</description>
</method>
<method name="set_custom_play_space">
<return type="void" />
<param index="0" name="space" type="const void*" />
<description>
Sets the reference space used by OpenXR to the given [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSpace.html]XrSpace[/url] (cast to a [code]void *[/code]).
</description>
</method>
<method name="set_emulate_environment_blend_mode_alpha_blend">
<return type="void" />
<param index="0" name="enabled" type="bool" />
@ -295,6 +309,13 @@
Unregisters the given extension as a composition layer provider.
</description>
</method>
<method name="unregister_frame_info_extension">
<return type="void" />
<param index="0" name="extension" type="OpenXRExtensionWrapper" />
<description>
Unregisters the given extension as modifying frame info.
</description>
</method>
<method name="unregister_projection_views_extension">
<return type="void" />
<param index="0" name="extension" type="OpenXRExtensionWrapper" />

@ -202,6 +202,22 @@
[param property_values] contains the values of the properties returned by [method _get_viewport_composition_layer_extension_properties].
</description>
</method>
<method name="_set_frame_end_info_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="next_pointer" type="void*" />
<description>
Adds additional data structures to [code]XrFrameEndInfo[/code].
This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_frame_info_extension].
</description>
</method>
<method name="_set_frame_wait_info_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="next_pointer" type="void*" />
<description>
Adds additional data structures to [code]XrFrameWaitInfo[/code].
This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_frame_info_extension].
</description>
</method>
<method name="_set_hand_joint_locations_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="hand_index" type="int" />
@ -225,6 +241,14 @@
Adds additional data structures to the projection view of the given [param view_index].
</description>
</method>
<method name="_set_reference_space_create_info_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="reference_space_type" type="int" />
<param index="1" name="next_pointer" type="void*" />
<description>
Adds additional data structures to [code]XrReferenceSpaceCreateInfo[/code].
</description>
</method>
<method name="_set_session_create_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="next_pointer" type="void*" />
@ -246,6 +270,14 @@
Adds additional data structures when querying OpenXR system abilities.
</description>
</method>
<method name="_set_view_locate_info_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="next_pointer" type="void*" />
<description>
Adds additional data structures to [code]XrViewLocateInfo[/code].
This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_frame_info_extension].
</description>
</method>
<method name="_set_viewport_composition_layer_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="layer" type="const void*" />

@ -41,6 +41,10 @@ void OpenXRExtensionWrapper::_bind_methods() {
GDVIRTUAL_BIND(_set_swapchain_create_info_and_get_next_pointer, "next_pointer");
GDVIRTUAL_BIND(_set_hand_joint_locations_and_get_next_pointer, "hand_index", "next_pointer");
GDVIRTUAL_BIND(_set_projection_views_and_get_next_pointer, "view_index", "next_pointer");
GDVIRTUAL_BIND(_set_frame_wait_info_and_get_next_pointer, "next_pointer");
GDVIRTUAL_BIND(_set_frame_end_info_and_get_next_pointer, "next_pointer");
GDVIRTUAL_BIND(_set_view_locate_info_and_get_next_pointer, "next_pointer");
GDVIRTUAL_BIND(_set_reference_space_create_info_and_get_next_pointer, "reference_space_type", "next_pointer");
GDVIRTUAL_BIND(_get_composition_layer_count);
GDVIRTUAL_BIND(_get_composition_layer, "index");
GDVIRTUAL_BIND(_get_composition_layer_order, "index");
@ -152,6 +156,46 @@ void *OpenXRExtensionWrapper::set_projection_views_and_get_next_pointer(int p_vi
return nullptr;
}
void *OpenXRExtensionWrapper::set_reference_space_create_info_and_get_next_pointer(int p_reference_space_type, void *p_next_pointer) {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_set_reference_space_create_info_and_get_next_pointer, p_reference_space_type, GDExtensionPtr<void>(p_next_pointer), pointer)) {
return reinterpret_cast<void *>(pointer);
}
return nullptr;
}
void *OpenXRExtensionWrapper::set_frame_wait_info_and_get_next_pointer(void *p_next_pointer) {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_set_frame_wait_info_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
return reinterpret_cast<void *>(pointer);
}
return nullptr;
}
void *OpenXRExtensionWrapper::set_frame_end_info_and_get_next_pointer(void *p_next_pointer) {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_set_frame_end_info_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
return reinterpret_cast<void *>(pointer);
}
return nullptr;
}
void *OpenXRExtensionWrapper::set_view_locate_info_and_get_next_pointer(void *p_next_pointer) {
uint64_t pointer = 0;
if (GDVIRTUAL_CALL(_set_view_locate_info_and_get_next_pointer, GDExtensionPtr<void>(p_next_pointer), pointer)) {
return reinterpret_cast<void *>(pointer);
}
return nullptr;
}
PackedStringArray OpenXRExtensionWrapper::get_suggested_tracker_names() {
PackedStringArray ret;

@ -77,6 +77,11 @@ public:
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when creating OpenXR swap chains.
virtual void *set_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer);
virtual void *set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer);
virtual void *set_reference_space_create_info_and_get_next_pointer(int p_reference_space_type, void *p_next_pointer);
// These will only be called for extensions registered via OpenXRApi::register_frame_info_extension().
virtual void *set_frame_wait_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when calling xrWaitFrame
virtual void *set_view_locate_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when calling xrLocateViews
virtual void *set_frame_end_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when calling xrEndFrame
//TODO workaround as GDExtensionPtr<void> return type results in build error in godot-cpp
GDVIRTUAL1R(uint64_t, _set_system_properties_and_get_next_pointer, GDExtensionPtr<void>);
@ -85,6 +90,10 @@ public:
GDVIRTUAL1R(uint64_t, _set_swapchain_create_info_and_get_next_pointer, GDExtensionPtr<void>);
GDVIRTUAL2R(uint64_t, _set_hand_joint_locations_and_get_next_pointer, int, GDExtensionPtr<void>);
GDVIRTUAL2R(uint64_t, _set_projection_views_and_get_next_pointer, int, GDExtensionPtr<void>);
GDVIRTUAL1R(uint64_t, _set_frame_wait_info_and_get_next_pointer, GDExtensionPtr<void>);
GDVIRTUAL1R(uint64_t, _set_frame_end_info_and_get_next_pointer, GDExtensionPtr<void>);
GDVIRTUAL1R(uint64_t, _set_view_locate_info_and_get_next_pointer, GDExtensionPtr<void>);
GDVIRTUAL2R(uint64_t, _set_reference_space_create_info_and_get_next_pointer, int, GDExtensionPtr<void>);
GDVIRTUAL0R(int, _get_composition_layer_count);
GDVIRTUAL1R(uint64_t, _get_composition_layer, int);
GDVIRTUAL1R(int, _get_composition_layer_order, int);

@ -927,7 +927,11 @@ bool OpenXRAPI::setup_play_space() {
XrSpace new_play_space = XR_NULL_HANDLE;
bool will_emulate_local_floor = false;
if (is_reference_space_supported(requested_reference_space)) {
if (custom_play_space != XR_NULL_HANDLE) {
new_play_space = custom_play_space;
// We use this to mark custom reference spaces.
new_reference_space = XR_REFERENCE_SPACE_TYPE_MAX_ENUM;
} else if (is_reference_space_supported(requested_reference_space)) {
new_reference_space = requested_reference_space;
} else if (requested_reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT && is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_STAGE)) {
print_verbose("OpenXR: LOCAL_FLOOR space isn't supported, emulating using STAGE and LOCAL spaces.");
@ -985,21 +989,34 @@ bool OpenXRAPI::setup_play_space() {
new_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
}
XrReferenceSpaceCreateInfo play_space_create_info = {
XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
nullptr, // next
new_reference_space, // referenceSpaceType
identityPose, // poseInReferenceSpace
};
if (new_play_space == XR_NULL_HANDLE) {
void *next_pointer = nullptr;
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
void *np = wrapper->set_reference_space_create_info_and_get_next_pointer(
new_reference_space, next_pointer);
if (np != nullptr) {
next_pointer = np;
}
}
XrResult result = xrCreateReferenceSpace(session, &play_space_create_info, &new_play_space);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to create play space [", get_error_string(result), "]");
return false;
XrReferenceSpaceCreateInfo play_space_create_info = {
XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
next_pointer, // next
new_reference_space, // referenceSpaceType
identityPose, // poseInReferenceSpace
};
XrResult result = xrCreateReferenceSpace(session, &play_space_create_info, &new_play_space);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to create play space [", get_error_string(result), "]");
return false;
}
}
// If we've previously created a play space, clean it up first.
if (play_space != XR_NULL_HANDLE) {
// But if it was a custom reference space, we don't touch it - it's the job of the extension that
// created it to clean it up.
if (play_space != XR_NULL_HANDLE && reference_space != XR_REFERENCE_SPACE_TYPE_MAX_ENUM) {
// TODO Investigate if destroying our play space here is safe,
// it may still be used in the rendering thread.
@ -1032,9 +1049,17 @@ bool OpenXRAPI::setup_view_space() {
{ 0.0, 0.0, 0.0 }
};
void *next_pointer = nullptr;
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
void *np = wrapper->set_reference_space_create_info_and_get_next_pointer(XR_REFERENCE_SPACE_TYPE_VIEW, next_pointer);
if (np != nullptr) {
next_pointer = np;
}
}
XrReferenceSpaceCreateInfo view_space_create_info = {
XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type
nullptr, // next
next_pointer, // next
XR_REFERENCE_SPACE_TYPE_VIEW, // referenceSpaceType
identityPose // poseInReferenceSpace
};
@ -1084,6 +1109,17 @@ bool OpenXRAPI::reset_emulated_floor_height() {
};
XrSpace new_play_space;
void *next_pointer = nullptr;
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
void *np = wrapper->set_reference_space_create_info_and_get_next_pointer(
create_info.referenceSpaceType, next_pointer);
if (np != nullptr) {
next_pointer = np;
}
}
create_info.next = next_pointer;
result = xrCreateReferenceSpace(session, &create_info, &new_play_space);
if (XR_FAILED(result)) {
print_line("OpenXR: Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate [", get_error_string(result), "]");
@ -1481,12 +1517,21 @@ void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configurat
}
bool OpenXRAPI::set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space) {
if (custom_play_space != XR_NULL_HANDLE) {
return false;
}
requested_reference_space = p_requested_reference_space;
play_space_is_dirty = true;
return true;
}
void OpenXRAPI::set_custom_play_space(XrSpace p_custom_space) {
custom_play_space = p_custom_space;
play_space_is_dirty = true;
}
void OpenXRAPI::set_submit_depth_buffer(bool p_submit_depth_buffer) {
ERR_FAIL_COND(is_initialized());
@ -2117,7 +2162,15 @@ bool OpenXRAPI::process() {
// As the name suggests, OpenXR can pause the thread to minimize the time between
// retrieving tracking data and using that tracking data to render.
// OpenXR thus works best if rendering is performed on a separate thread.
XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr };
void *frame_wait_info_next_pointer = nullptr;
for (OpenXRExtensionWrapper *extension : frame_info_extensions) {
void *np = extension->set_frame_wait_info_and_get_next_pointer(frame_wait_info_next_pointer);
if (np != nullptr) {
frame_wait_info_next_pointer = np;
}
}
XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, frame_wait_info_next_pointer };
frame_state.predictedDisplayTime = 0;
frame_state.predictedDisplayPeriod = 0;
frame_state.shouldRender = false;
@ -2195,6 +2248,14 @@ void OpenXRAPI::pre_render() {
wrapper->on_pre_render();
}
void *view_locate_info_next_pointer = nullptr;
for (OpenXRExtensionWrapper *extension : frame_info_extensions) {
void *np = extension->set_view_locate_info_and_get_next_pointer(view_locate_info_next_pointer);
if (np != nullptr) {
view_locate_info_next_pointer = np;
}
}
// Get our view info for the frame we're about to render, note from the OpenXR manual:
// "Repeatedly calling xrLocateViews with the same time may not necessarily return the same result. Instead the prediction gets increasingly accurate as the function is called closer to the given time for which a prediction is made"
@ -2208,7 +2269,7 @@ void OpenXRAPI::pre_render() {
XrViewLocateInfo view_locate_info = {
XR_TYPE_VIEW_LOCATE_INFO, // type
nullptr, // next
view_locate_info_next_pointer, // next
view_configuration, // viewConfigurationType
render_state.predicted_display_time, // displayTime
render_state.play_space // space
@ -2251,7 +2312,7 @@ void OpenXRAPI::pre_render() {
};
result = xrBeginFrame(session, &frame_begin_info);
if (XR_FAILED(result)) {
print_line("OpenXR: failed to being frame [", get_error_string(result), "]");
print_line("OpenXR: failed to begin frame [", get_error_string(result), "]");
return;
}
@ -2482,9 +2543,17 @@ void OpenXRAPI::end_frame() {
layers_list.push_back(ordered_layer.composition_layer);
}
void *frame_end_info_next_pointer = nullptr;
for (OpenXRExtensionWrapper *extension : frame_info_extensions) {
void *np = extension->set_frame_end_info_and_get_next_pointer(frame_end_info_next_pointer);
if (np != nullptr) {
frame_end_info_next_pointer = np;
}
}
XrFrameEndInfo frame_end_info = {
XR_TYPE_FRAME_END_INFO, // type
nullptr, // next
frame_end_info_next_pointer, // next
render_state.predicted_display_time, // displayTime
environment_blend_mode, // environmentBlendMode
static_cast<uint32_t>(layers_list.size()), // layerCount
@ -2690,6 +2759,7 @@ OpenXRAPI::OpenXRAPI() {
OpenXRAPI::~OpenXRAPI() {
composition_layer_providers.clear();
frame_info_extensions.clear();
supported_extensions.clear();
layer_properties.clear();
@ -3611,6 +3681,14 @@ void OpenXRAPI::unregister_projection_views_extension(OpenXRExtensionWrapper *p_
projection_views_extensions.erase(p_extension);
}
void OpenXRAPI::register_frame_info_extension(OpenXRExtensionWrapper *p_extension) {
frame_info_extensions.append(p_extension);
}
void OpenXRAPI::unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension) {
frame_info_extensions.erase(p_extension);
}
const Vector<XrEnvironmentBlendMode> OpenXRAPI::get_supported_environment_blend_modes() {
return supported_environment_blend_modes;
}

@ -98,6 +98,9 @@ private:
// projection views extensions
Vector<OpenXRExtensionWrapper *> projection_views_extensions;
// frame info extensions
Vector<OpenXRExtensionWrapper *> frame_info_extensions;
// view configuration
LocalVector<XrViewConfigurationType> supported_view_configuration_types;
@ -153,6 +156,7 @@ private:
bool play_space_is_dirty = true;
XrSpace play_space = XR_NULL_HANDLE;
XrSpace custom_play_space = XR_NULL_HANDLE;
XrSpace view_space = XR_NULL_HANDLE;
XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
@ -465,6 +469,7 @@ public:
bool set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space);
XrReferenceSpaceType get_requested_reference_space() const { return requested_reference_space; }
XrReferenceSpaceType get_reference_space() const { return reference_space; }
void set_custom_play_space(XrSpace p_custom_space);
void set_submit_depth_buffer(bool p_submit_depth_buffer);
bool get_submit_depth_buffer() const { return submit_depth_buffer; }
@ -582,6 +587,9 @@ public:
void register_projection_views_extension(OpenXRExtensionWrapper *p_extension);
void unregister_projection_views_extension(OpenXRExtensionWrapper *p_extension);
void register_frame_info_extension(OpenXRExtensionWrapper *p_extension);
void unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension);
const Vector<XrEnvironmentBlendMode> get_supported_environment_blend_modes();
bool is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const;
bool set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode);

@ -52,6 +52,7 @@ void OpenXRAPIExtension::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_initialized"), &OpenXRAPIExtension::is_initialized);
ClassDB::bind_method(D_METHOD("is_running"), &OpenXRAPIExtension::is_running);
ClassDB::bind_method(D_METHOD("set_custom_play_space", "space"), &OpenXRAPIExtension::set_custom_play_space);
ClassDB::bind_method(D_METHOD("get_play_space"), &OpenXRAPIExtension::get_play_space);
ClassDB::bind_method(D_METHOD("get_predicted_display_time"), &OpenXRAPIExtension::get_predicted_display_time);
ClassDB::bind_method(D_METHOD("get_next_frame_time"), &OpenXRAPIExtension::get_next_frame_time);
@ -68,6 +69,9 @@ void OpenXRAPIExtension::_bind_methods() {
ClassDB::bind_method(D_METHOD("register_projection_views_extension", "extension"), &OpenXRAPIExtension::register_projection_views_extension);
ClassDB::bind_method(D_METHOD("unregister_projection_views_extension", "extension"), &OpenXRAPIExtension::unregister_projection_views_extension);
ClassDB::bind_method(D_METHOD("register_frame_info_extension", "extension"), &OpenXRAPIExtension::register_frame_info_extension);
ClassDB::bind_method(D_METHOD("unregister_frame_info_extension", "extension"), &OpenXRAPIExtension::unregister_frame_info_extension);
ClassDB::bind_method(D_METHOD("get_render_state_z_near"), &OpenXRAPIExtension::get_render_state_z_near);
ClassDB::bind_method(D_METHOD("get_render_state_z_far"), &OpenXRAPIExtension::get_render_state_z_far);
@ -181,6 +185,11 @@ bool OpenXRAPIExtension::is_running() {
return OpenXRAPI::get_singleton()->is_running();
}
void OpenXRAPIExtension::set_custom_play_space(GDExtensionConstPtr<const void> p_custom_space) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->set_custom_play_space(*(XrSpace *)p_custom_space.data);
}
uint64_t OpenXRAPIExtension::get_play_space() {
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0);
return (uint64_t)OpenXRAPI::get_singleton()->get_play_space();
@ -241,6 +250,16 @@ void OpenXRAPIExtension::unregister_projection_views_extension(OpenXRExtensionWr
OpenXRAPI::get_singleton()->unregister_projection_views_extension(p_extension);
}
void OpenXRAPIExtension::register_frame_info_extension(OpenXRExtensionWrapper *p_extension) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->register_frame_info_extension(p_extension);
}
void OpenXRAPIExtension::unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension) {
ERR_FAIL_NULL(OpenXRAPI::get_singleton());
OpenXRAPI::get_singleton()->unregister_frame_info_extension(p_extension);
}
double OpenXRAPIExtension::get_render_state_z_near() {
ERR_NOT_ON_RENDER_THREAD_V(0.0);
ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0.0);

@ -79,6 +79,7 @@ public:
bool is_initialized();
bool is_running();
void set_custom_play_space(GDExtensionConstPtr<const void> p_custom_space);
uint64_t get_play_space();
int64_t get_predicted_display_time();
int64_t get_next_frame_time();
@ -95,6 +96,9 @@ public:
void register_projection_views_extension(OpenXRExtensionWrapper *p_extension);
void unregister_projection_views_extension(OpenXRExtensionWrapper *p_extension);
void register_frame_info_extension(OpenXRExtensionWrapper *p_extension);
void unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension);
double get_render_state_z_near();
double get_render_state_z_far();

@ -753,6 +753,8 @@ XRInterface::PlayAreaMode OpenXRInterface::get_play_area_mode() const {
return XRInterface::XR_PLAY_AREA_ROOMSCALE;
} else if (reference_space == XR_REFERENCE_SPACE_TYPE_STAGE) {
return XRInterface::XR_PLAY_AREA_STAGE;
} else if (reference_space == XR_REFERENCE_SPACE_TYPE_MAX_ENUM) {
return XRInterface::XR_PLAY_AREA_CUSTOM;
}
return XRInterface::XR_PLAY_AREA_UNKNOWN;

@ -103,6 +103,7 @@ void XRInterface::_bind_methods() {
BIND_ENUM_CONSTANT(XR_PLAY_AREA_SITTING);
BIND_ENUM_CONSTANT(XR_PLAY_AREA_ROOMSCALE);
BIND_ENUM_CONSTANT(XR_PLAY_AREA_STAGE);
BIND_ENUM_CONSTANT(XR_PLAY_AREA_CUSTOM);
BIND_ENUM_CONSTANT(XR_ENV_BLEND_MODE_OPAQUE);
BIND_ENUM_CONSTANT(XR_ENV_BLEND_MODE_ADDITIVE);

@ -76,6 +76,7 @@ public:
XR_PLAY_AREA_SITTING, /* Player is in seated position, limited positional tracking, fixed guardian around player */
XR_PLAY_AREA_ROOMSCALE, /* Player is free to move around, full positional tracking */
XR_PLAY_AREA_STAGE, /* Same as roomscale but origin point is fixed to the center of the physical space */
XR_PLAY_AREA_CUSTOM = 0x7FFFFFFF, /* Used to denote that a custom, possibly non-standard, play area is being used */
};
enum EnvironmentBlendMode {