diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index d3b124dcde58..4a1775c70ad5 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -2709,6 +2709,9 @@ If [code]true[/code] Godot will setup and initialize OpenXR on startup. + + Specify how OpenXR should blend in the environment. This is specific to certain AR and passthrough devices where camera images are blended in by the XR compositor. + Specify whether OpenXR should be configured for an HMD or a hand held device. diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml index 7b741b43d854..99d6e67e5196 100644 --- a/doc/classes/XRInterface.xml +++ b/doc/classes/XRInterface.xml @@ -188,6 +188,9 @@ On an AR interface, [code]true[/code] if anchor detection is enabled. + + Specify how XR should blend in the environment. This is specific to certain AR and passthrough devices where camera images are blended in by the XR compositor. + [code]true[/code] if this is the primary interface. diff --git a/main/main.cpp b/main/main.cpp index aa2f5f2451a1..e24690f9926a 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2048,6 +2048,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/form_factor", PROPERTY_HINT_ENUM, "Head Mounted,Handheld"), "0"); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/view_configuration", PROPERTY_HINT_ENUM, "Mono,Stereo"), "1"); // "Mono,Stereo,Quad,Observer" GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage"), "1"); + GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/environment_blend_mode", PROPERTY_HINT_ENUM, "Opaque,Additive,Alpha"), "0"); GLOBAL_DEF_BASIC("xr/openxr/submit_depth_buffer", false); GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true); diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index a66afee1c527..e4dd9f266591 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -481,11 +481,19 @@ bool OpenXRAPI::load_supported_view_configuration_types() { result = xrEnumerateViewConfigurations(instance, system_id, num_view_configuration_types, &num_view_configuration_types, supported_view_configuration_types); ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerateview configurations"); + ERR_FAIL_COND_V_MSG(num_view_configuration_types == 0, false, "OpenXR: Failed to enumerateview configurations"); // JIC there should be at least 1! for (uint32_t i = 0; i < num_view_configuration_types; i++) { print_verbose(String("OpenXR: Found supported view configuration ") + OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[i])); } + // Check value we loaded at startup... + if (!is_view_configuration_supported(view_configuration)) { + print_verbose(String("OpenXR: ") + OpenXRUtil::get_view_configuration_name(view_configuration) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[0])); + + view_configuration = supported_view_configuration_types[0]; + } + return true; } @@ -512,11 +520,19 @@ bool OpenXRAPI::load_supported_environmental_blend_modes() { result = xrEnumerateEnvironmentBlendModes(instance, system_id, view_configuration, num_supported_environment_blend_modes, &num_supported_environment_blend_modes, supported_environment_blend_modes); ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate environmental blend modes"); + ERR_FAIL_COND_V_MSG(num_supported_environment_blend_modes == 0, false, "OpenXR: Failed to enumerate environmental blend modes"); // JIC there should be at least 1! for (uint32_t i = 0; i < num_supported_environment_blend_modes; i++) { print_verbose(String("OpenXR: Found environmental blend mode ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[i])); } + // Check value we loaded at startup... + if (!is_environment_blend_mode_supported(environment_blend_mode)) { + print_verbose(String("OpenXR: ") + OpenXRUtil::get_environment_blend_mode_name(environment_blend_mode) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[0])); + + environment_blend_mode = supported_environment_blend_modes[0]; + } + return true; } @@ -665,11 +681,19 @@ bool OpenXRAPI::load_supported_reference_spaces() { result = xrEnumerateReferenceSpaces(session, num_reference_spaces, &num_reference_spaces, supported_reference_spaces); ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate reference spaces"); + ERR_FAIL_COND_V_MSG(num_reference_spaces == 0, false, "OpenXR: Failed to enumerate reference spaces"); for (uint32_t i = 0; i < num_reference_spaces; i++) { print_verbose(String("OpenXR: Found supported reference space ") + OpenXRUtil::get_reference_space_name(supported_reference_spaces[i])); } + // Check value we loaded at startup... + if (!is_reference_space_supported(reference_space)) { + print_verbose(String("OpenXR: ") + OpenXRUtil::get_reference_space_name(reference_space) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_reference_space_name(supported_reference_spaces[0])); + + reference_space = supported_reference_spaces[0]; + } + return true; } @@ -1917,10 +1941,15 @@ void OpenXRAPI::end_frame() { } } + XrCompositionLayerFlags layer_flags = XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT; + if (layers_list.size() > 0 || environment_blend_mode != XR_ENVIRONMENT_BLEND_MODE_OPAQUE) { + layer_flags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; + } + XrCompositionLayerProjection projection_layer = { XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type nullptr, // next - layers_list.size() > 0 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags + layer_flags, // layerFlags play_space, // space view_count, // viewCount projection_views, // views @@ -1984,8 +2013,8 @@ OpenXRAPI::OpenXRAPI() { } else { // Load settings from project settings - int ff = GLOBAL_GET("xr/openxr/form_factor"); - switch (ff) { + int form_factor_setting = GLOBAL_GET("xr/openxr/form_factor"); + switch (form_factor_setting) { case 0: { form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; } break; @@ -1996,8 +2025,8 @@ OpenXRAPI::OpenXRAPI() { break; } - int vc = GLOBAL_GET("xr/openxr/view_configuration"); - switch (vc) { + int view_configuration_setting = GLOBAL_GET("xr/openxr/view_configuration"); + switch (view_configuration_setting) { case 0: { view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO; } break; @@ -2016,8 +2045,8 @@ OpenXRAPI::OpenXRAPI() { break; } - int rs = GLOBAL_GET("xr/openxr/reference_space"); - switch (rs) { + int reference_space_setting = GLOBAL_GET("xr/openxr/reference_space"); + switch (reference_space_setting) { case 0: { reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL; } break; @@ -2028,6 +2057,21 @@ OpenXRAPI::OpenXRAPI() { break; } + int environment_blend_mode_setting = GLOBAL_GET("xr/openxr/environment_blend_mode"); + switch (environment_blend_mode_setting) { + case 0: { + environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; + } break; + case 1: { + environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE; + } break; + case 2: { + environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND; + } break; + default: + break; + } + submit_depth_buffer = GLOBAL_GET("xr/openxr/submit_depth_buffer"); } @@ -2857,12 +2901,24 @@ const XrEnvironmentBlendMode *OpenXRAPI::get_supported_environment_blend_modes(u return supported_environment_blend_modes; } -bool OpenXRAPI::set_environment_blend_mode(XrEnvironmentBlendMode mode) { +bool OpenXRAPI::is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const { + ERR_FAIL_NULL_V(supported_environment_blend_modes, false); + for (uint32_t i = 0; i < num_supported_environment_blend_modes; i++) { - if (supported_environment_blend_modes[i] == mode) { - environment_blend_mode = mode; + if (supported_environment_blend_modes[i] == p_blend_mode) { return true; } } + + return false; +} + +bool OpenXRAPI::set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode) { + // We allow setting this when not initialised and will check if it is supported when initialising. + // After OpenXR is initialised we verify we're setting a supported blend mode. + if (!is_initialized() || is_environment_blend_mode_supported(p_blend_mode)) { + environment_blend_mode = p_blend_mode; + return true; + } return false; } diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 6d1c731e7ae6..26de53515315 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -405,7 +405,9 @@ public: void unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider); const XrEnvironmentBlendMode *get_supported_environment_blend_modes(uint32_t &count); - bool set_environment_blend_mode(XrEnvironmentBlendMode mode); + bool is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const; + bool set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode); + XrEnvironmentBlendMode get_environment_blend_mode() const { return environment_blend_mode; } OpenXRAPI(); ~OpenXRAPI(); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 4dda51147be2..cf8d1654b1e0 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -985,6 +985,27 @@ Array OpenXRInterface::get_supported_environment_blend_modes() { return modes; } +XRInterface::EnvironmentBlendMode OpenXRInterface::get_environment_blend_mode() const { + if (openxr_api) { + XrEnvironmentBlendMode oxr_blend_mode = openxr_api->get_environment_blend_mode(); + switch (oxr_blend_mode) { + case XR_ENVIRONMENT_BLEND_MODE_OPAQUE: { + return XR_ENV_BLEND_MODE_OPAQUE; + } break; + case XR_ENVIRONMENT_BLEND_MODE_ADDITIVE: { + return XR_ENV_BLEND_MODE_ADDITIVE; + } break; + case XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND: { + return XR_ENV_BLEND_MODE_ALPHA_BLEND; + } break; + default: + break; + } + } + + return XR_ENV_BLEND_MODE_OPAQUE; +} + bool OpenXRInterface::set_environment_blend_mode(XRInterface::EnvironmentBlendMode mode) { if (openxr_api) { XrEnvironmentBlendMode oxr_blend_mode; diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index 09e1c31728ce..81efbd677701 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -152,6 +152,7 @@ public: /** environment blend mode. */ virtual Array get_supported_environment_blend_modes() override; + virtual XRInterface::EnvironmentBlendMode get_environment_blend_mode() const override; virtual bool set_environment_blend_mode(XRInterface::EnvironmentBlendMode mode) override; void on_state_ready(); diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index 416f08dbb6e4..9ced28fd52da 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -79,6 +79,8 @@ void XRInterface::_bind_methods() { /** environment blend mode. */ ClassDB::bind_method(D_METHOD("get_supported_environment_blend_modes"), &XRInterface::get_supported_environment_blend_modes); ClassDB::bind_method(D_METHOD("set_environment_blend_mode", "mode"), &XRInterface::set_environment_blend_mode); + ClassDB::bind_method(D_METHOD("get_environment_blend_mode"), &XRInterface::get_environment_blend_mode); + ADD_PROPERTY(PropertyInfo(Variant::INT, "environment_blend_mode"), "set_environment_blend_mode", "get_environment_blend_mode"); ADD_GROUP("AR", "ar_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ar_is_anchor_detection_enabled"), "set_anchor_detection_is_enabled", "get_anchor_detection_is_enabled"); diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index b42cb3723440..c76d0fbf68a0 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -147,6 +147,7 @@ public: /** environment blend mode. */ virtual Array get_supported_environment_blend_modes(); + virtual XRInterface::EnvironmentBlendMode get_environment_blend_mode() const { return XR_ENV_BLEND_MODE_OPAQUE; } virtual bool set_environment_blend_mode(EnvironmentBlendMode mode) { return false; } XRInterface();