diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/mobile_vr/doc_classes/MobileVRInterface.xml | 8 | ||||
-rw-r--r-- | modules/mobile_vr/mobile_vr_interface.cpp | 54 | ||||
-rw-r--r-- | modules/mobile_vr/mobile_vr_interface.h | 11 | ||||
-rw-r--r-- | modules/openxr/doc_classes/OpenXRInterface.xml | 8 | ||||
-rw-r--r-- | modules/openxr/extensions/openxr_eye_gaze_interaction.cpp | 36 | ||||
-rw-r--r-- | modules/openxr/extensions/openxr_eye_gaze_interaction.h | 6 | ||||
-rw-r--r-- | modules/openxr/openxr_api.cpp | 85 | ||||
-rw-r--r-- | modules/openxr/openxr_api.h | 4 | ||||
-rw-r--r-- | modules/openxr/openxr_interface.cpp | 44 | ||||
-rw-r--r-- | modules/openxr/openxr_interface.h | 10 |
10 files changed, 254 insertions, 12 deletions
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml index 8338054142..0dbe06d220 100644 --- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml +++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml @@ -40,6 +40,14 @@ <member name="oversample" type="float" setter="set_oversample" getter="get_oversample" default="1.5"> The oversample setting. Because of the lens distortion we have to render our buffers at a higher resolution then the screen can natively handle. A value between 1.5 and 2.0 often provides good results but at the cost of performance. </member> + <member name="vrs_min_radius" type="float" setter="set_vrs_min_radius" getter="get_vrs_min_radius" default="20.0"> + The minimum radius around the focal point where full quality is guaranteed if VRS is used as a percentage of screen size. + [b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR]. + </member> + <member name="vrs_strength" type="float" setter="set_vrs_strength" getter="get_vrs_strength" default="1.0"> + The strength used to calculate the VRS density map. The greater this value, the more noticeable VRS is. This improves performance at the cost of quality. + [b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR]. + </member> <member name="xr_play_area_mode" type="int" setter="set_play_area_mode" getter="get_play_area_mode" overrides="XRInterface" enum="XRInterface.PlayAreaMode" default="1" /> </members> </class> diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index d23edcd1d1..f27281866a 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -250,6 +250,16 @@ void MobileVRInterface::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversample", PROPERTY_HINT_RANGE, "1.0,2.0,0.1"), "set_oversample", "get_oversample"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "k1", PROPERTY_HINT_RANGE, "0.1,10.0,0.0001"), "set_k1", "get_k1"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "k2", PROPERTY_HINT_RANGE, "0.1,10.0,0.0001"), "set_k2", "get_k2"); + + ClassDB::bind_method(D_METHOD("get_vrs_min_radius"), &MobileVRInterface::get_vrs_min_radius); + ClassDB::bind_method(D_METHOD("set_vrs_min_radius", "radius"), &MobileVRInterface::set_vrs_min_radius); + + ClassDB::bind_method(D_METHOD("get_vrs_strength"), &MobileVRInterface::get_vrs_strength); + ClassDB::bind_method(D_METHOD("set_vrs_strength", "strength"), &MobileVRInterface::set_vrs_strength); + + ADD_GROUP("Vulkan VRS", "vrs_"); + 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"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_strength", PROPERTY_HINT_RANGE, "0.1,10.0,0.1"), "set_vrs_strength", "get_vrs_strength"); } void MobileVRInterface::set_eye_height(const double p_eye_height) { @@ -316,6 +326,22 @@ double MobileVRInterface::get_k2() const { return k2; }; +float MobileVRInterface::get_vrs_min_radius() const { + return xr_vrs.get_vrs_min_radius(); +} + +void MobileVRInterface::set_vrs_min_radius(float p_vrs_min_radius) { + xr_vrs.set_vrs_min_radius(p_vrs_min_radius); +} + +float MobileVRInterface::get_vrs_strength() const { + return xr_vrs.get_vrs_strength(); +} + +void MobileVRInterface::set_vrs_strength(float p_vrs_strength) { + xr_vrs.set_vrs_strength(p_vrs_strength); +} + uint32_t MobileVRInterface::get_view_count() { // needs stereo... return 2; @@ -489,11 +515,16 @@ Vector<BlitToScreen> MobileVRInterface::post_draw_viewport(RID p_render_target, Vector<BlitToScreen> blit_to_screen; - // We must have a valid render target + // We must have a valid render target. ERR_FAIL_COND_V(!p_render_target.is_valid(), blit_to_screen); - // Because we are rendering to our device we must use our main viewport! - ERR_FAIL_COND_V(p_screen_rect == Rect2(), blit_to_screen); + // We will only output to screen if this is our main viewport. + if (p_screen_rect == Rect2()) { + // Warn the developer once, it's up to the developer to output to screen. + WARN_PRINT_ONCE("SubViewport used with MobileVRInterface, no output to screen"); + + return blit_to_screen; + } Rect2 modified_screen_rect = Rect2(p_screen_rect.position + offset_rect.position * p_screen_rect.size, p_screen_rect.size * offset_rect.size); @@ -542,6 +573,23 @@ void MobileVRInterface::process() { }; }; +RID MobileVRInterface::get_vrs_texture() { + PackedVector2Array eye_foci; + + Size2 target_size = get_render_target_size(); + real_t aspect_ratio = target_size.x / target_size.y; + uint32_t view_count = get_view_count(); + + for (uint32_t v = 0; v < view_count; v++) { + Projection cm = get_projection_for_view(v, aspect_ratio, 0.1, 1000.0); + Vector3 center = cm.xform(Vector3(0.0, 0.0, 999.0)); + + eye_foci.push_back(Vector2(center.x, center.y)); + } + + return xr_vrs.make_vrs_texture(target_size, eye_foci); +} + MobileVRInterface::MobileVRInterface() {} MobileVRInterface::~MobileVRInterface() { diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h index e1d43fff74..490b1c393c 100644 --- a/modules/mobile_vr/mobile_vr_interface.h +++ b/modules/mobile_vr/mobile_vr_interface.h @@ -33,6 +33,7 @@ #include "servers/xr/xr_interface.h" #include "servers/xr/xr_positional_tracker.h" +#include "servers/xr/xr_vrs.h" /** The mobile interface is a native VR interface that can be used on Android and iOS phones. @@ -72,6 +73,8 @@ private: Ref<XRPositionalTracker> head; Transform3D head_transform; + XRVRS xr_vrs; + /* logic for processing our sensor data, this was originally in our positional tracker logic but I think that doesn't make sense in hindsight. It only makes marginally more sense to park it here for now, @@ -138,6 +141,12 @@ public: void set_k2(const double p_k2); double get_k2() const; + float get_vrs_min_radius() const; + void set_vrs_min_radius(float p_vrs_min_radius); + + float get_vrs_strength() const; + void set_vrs_strength(float p_vrs_strength); + virtual StringName get_name() const override; virtual uint32_t get_capabilities() const override; @@ -161,6 +170,8 @@ public: virtual void process() override; + virtual RID get_vrs_texture() override; + MobileVRInterface(); ~MobileVRInterface(); }; diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index 86ba1416c8..309cbe0d72 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -152,6 +152,14 @@ <member name="render_target_size_multiplier" type="float" setter="set_render_target_size_multiplier" getter="get_render_target_size_multiplier" default="1.0"> The render size multiplier for the current HMD. Must be set before the interface has been initialized. </member> + <member name="vrs_min_radius" type="float" setter="set_vrs_min_radius" getter="get_vrs_min_radius" default="20.0"> + The minimum radius around the focal point where full quality is guaranteed if VRS is used as a percentage of screen size. + [b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR]. + </member> + <member name="vrs_strength" type="float" setter="set_vrs_strength" getter="get_vrs_strength" default="1.0"> + The strength used to calculate the VRS density map. The greater this value, the more noticeable VRS is. This improves performance at the cost of quality. + [b]Note:[/b] Mobile and Forward+ renderers only. Requires [member Viewport.vrs_mode] to be set to [constant Viewport.VRS_XR]. + </member> </members> <signals> <signal name="instance_exiting"> diff --git a/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp b/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp index 477a1c2609..eea996edd9 100644 --- a/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp +++ b/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp @@ -34,6 +34,7 @@ #include "core/os/os.h" #include "../action_map/openxr_interaction_profile_metadata.h" +#include "../openxr_api.h" OpenXREyeGazeInteractionExtension *OpenXREyeGazeInteractionExtension::singleton = nullptr; @@ -106,3 +107,38 @@ void OpenXREyeGazeInteractionExtension::on_register_metadata() { metadata->register_interaction_profile("Eye gaze", "/interaction_profiles/ext/eye_gaze_interaction", XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME); metadata->register_io_path("/interaction_profiles/ext/eye_gaze_interaction", "Gaze pose", "/user/eyes_ext", "/user/eyes_ext/input/gaze_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE); } + +bool OpenXREyeGazeInteractionExtension::get_eye_gaze_pose(double p_dist, Vector3 &r_eye_pose) { + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL_V(openxr_api, false); + + if (!init_eye_gaze_pose) { + init_eye_gaze_pose = true; + + eye_tracker = openxr_api->find_tracker("/user/eyes_ext"); + if (eye_tracker.is_null()) { + WARN_PRINT("Couldn't obtain eye tracker"); + } + + eye_action = openxr_api->find_action("eye_gaze_pose"); + if (eye_action.is_null()) { + WARN_PRINT("Couldn't obtain pose action for `eye_gaze_pose`, make sure to add this to your action map."); + } + } + + if (eye_tracker.is_null() || eye_action.is_null()) { + return false; + } + + Transform3D eye_transform; + Vector3 linear_velocity; + Vector3 angular_velocity; + XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(eye_action, eye_tracker, eye_transform, linear_velocity, angular_velocity); + if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) { + return false; + } + + r_eye_pose = eye_transform.origin + eye_transform.basis[2] * p_dist; + + return true; +} diff --git a/modules/openxr/extensions/openxr_eye_gaze_interaction.h b/modules/openxr/extensions/openxr_eye_gaze_interaction.h index 2b99f8edff..114c1aacc7 100644 --- a/modules/openxr/extensions/openxr_eye_gaze_interaction.h +++ b/modules/openxr/extensions/openxr_eye_gaze_interaction.h @@ -50,11 +50,17 @@ public: virtual void on_register_metadata() override; + bool get_eye_gaze_pose(double p_dist, Vector3 &r_eye_pose); + private: static OpenXREyeGazeInteractionExtension *singleton; bool available = false; XrSystemEyeGazeInteractionPropertiesEXT properties; + + bool init_eye_gaze_pose = false; + RID eye_tracker; + RID eye_action; }; #endif // OPENXR_EYE_GAZE_INTERACTION_H diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 40e3ecfefc..8731a36865 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -54,6 +54,7 @@ #endif #include "extensions/openxr_composition_layer_depth_extension.h" +#include "extensions/openxr_eye_gaze_interaction.h" #include "extensions/openxr_fb_display_refresh_rate_extension.h" #include "extensions/openxr_fb_foveation_extension.h" #include "extensions/openxr_fb_update_swapchain_extension.h" @@ -1826,6 +1827,46 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z return graphics_extension->create_projection_fov(render_state.views[p_view].fov, p_z_near, p_z_far, p_camera_matrix); } +Vector2 OpenXRAPI::get_eye_focus(uint32_t p_view, float p_aspect) { + ERR_FAIL_NULL_V(graphics_extension, Vector2()); + + if (!render_state.running) { + return Vector2(); + } + + // xrWaitFrame not run yet + if (render_state.predicted_display_time == 0) { + return Vector2(); + } + + // we don't have valid view info + if (render_state.views == nullptr || !render_state.view_pose_valid) { + return Vector2(); + } + + Projection cm; + if (!graphics_extension->create_projection_fov(render_state.views[p_view].fov, 0.1, 1000.0, cm)) { + return Vector2(); + } + + // Default focus to center... + Vector3 focus = cm.xform(Vector3(0.0, 0.0, 999.9)); + + // Lets check for eye tracking... + OpenXREyeGazeInteractionExtension *eye_gaze_interaction = OpenXREyeGazeInteractionExtension::get_singleton(); + if (eye_gaze_interaction && eye_gaze_interaction->supports_eye_gaze_interaction()) { + Vector3 eye_gaze_pose; + if (eye_gaze_interaction->get_eye_gaze_pose(1.0, eye_gaze_pose)) { + Transform3D view_transform = transform_from_pose(render_state.views[p_view].pose); + + eye_gaze_pose = view_transform.xform_inv(eye_gaze_pose); + focus = cm.xform(eye_gaze_pose); + } + } + + return Vector2(focus.x, focus.y); +} + bool OpenXRAPI::poll_events() { ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); @@ -2633,10 +2674,23 @@ bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const RID OpenXRAPI::get_tracker_rid(XrPath p_path) { List<RID> current; tracker_owner.get_owned_list(¤t); - for (int i = 0; i < current.size(); i++) { - Tracker *tracker = tracker_owner.get_or_null(current[i]); + for (const RID &E : current) { + Tracker *tracker = tracker_owner.get_or_null(E); if (tracker && tracker->toplevel_path == p_path) { - return current[i]; + return E; + } + } + + return RID(); +} + +RID OpenXRAPI::find_tracker(const String &p_name) { + List<RID> current; + tracker_owner.get_owned_list(¤t); + for (const RID &E : current) { + Tracker *tracker = tracker_owner.get_or_null(E); + if (tracker && tracker->name == p_name) { + return E; } } @@ -2827,10 +2881,23 @@ void OpenXRAPI::action_set_free(RID p_action_set) { RID OpenXRAPI::get_action_rid(XrAction p_action) { List<RID> current; action_owner.get_owned_list(¤t); - for (int i = 0; i < current.size(); i++) { - Action *action = action_owner.get_or_null(current[i]); + for (const RID &E : current) { + Action *action = action_owner.get_or_null(E); if (action && action->handle == p_action) { - return current[i]; + return E; + } + } + + return RID(); +} + +RID OpenXRAPI::find_action(const String &p_name) { + List<RID> current; + action_owner.get_owned_list(¤t); + for (const RID &E : current) { + Action *action = action_owner.get_or_null(E); + if (action && action->name == p_name) { + return E; } } @@ -2931,10 +2998,10 @@ void OpenXRAPI::action_free(RID p_action) { RID OpenXRAPI::get_interaction_profile_rid(XrPath p_path) { List<RID> current; interaction_profile_owner.get_owned_list(¤t); - for (int i = 0; i < current.size(); i++) { - InteractionProfile *ip = interaction_profile_owner.get_or_null(current[i]); + for (const RID &E : current) { + InteractionProfile *ip = interaction_profile_owner.get_or_null(E); if (ip && ip->path == p_path) { - return current[i]; + return E; } } diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index c95867810c..f9d2e60148 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -456,6 +456,7 @@ public: XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity); bool get_view_transform(uint32_t p_view, Transform3D &r_transform); bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix); + Vector2 get_eye_focus(uint32_t p_view, float p_aspect); bool process(); void pre_render(); @@ -515,6 +516,9 @@ public: bool interaction_profile_suggest_bindings(RID p_interaction_profile); void interaction_profile_free(RID p_interaction_profile); + RID find_tracker(const String &p_name); + RID find_action(const String &p_name); + bool sync_action_sets(const Vector<RID> p_active_sets); bool get_action_bool(RID p_action, RID p_tracker); float get_action_float(RID p_action, RID p_tracker); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 39a61d1b4d..b92d1edb90 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -97,6 +97,16 @@ void OpenXRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("is_hand_interaction_supported"), &OpenXRInterface::is_hand_interaction_supported); ClassDB::bind_method(D_METHOD("is_eye_gaze_interaction_supported"), &OpenXRInterface::is_eye_gaze_interaction_supported); + // VRS + ClassDB::bind_method(D_METHOD("get_vrs_min_radius"), &OpenXRInterface::get_vrs_min_radius); + ClassDB::bind_method(D_METHOD("set_vrs_min_radius", "radius"), &OpenXRInterface::set_vrs_min_radius); + ClassDB::bind_method(D_METHOD("get_vrs_strength"), &OpenXRInterface::get_vrs_strength); + ClassDB::bind_method(D_METHOD("set_vrs_strength", "strength"), &OpenXRInterface::set_vrs_strength); + + ADD_GROUP("Vulkan VRS", "vrs_"); + 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"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "vrs_strength", PROPERTY_HINT_RANGE, "0.1,10.0,0.1"), "set_vrs_strength", "get_vrs_strength"); + BIND_ENUM_CONSTANT(HAND_LEFT); BIND_ENUM_CONSTANT(HAND_RIGHT); BIND_ENUM_CONSTANT(HAND_MAX); @@ -872,6 +882,22 @@ Array OpenXRInterface::get_action_sets() const { return arr; } +float OpenXRInterface::get_vrs_min_radius() const { + return xr_vrs.get_vrs_min_radius(); +} + +void OpenXRInterface::set_vrs_min_radius(float p_vrs_min_radius) { + xr_vrs.set_vrs_min_radius(p_vrs_min_radius); +} + +float OpenXRInterface::get_vrs_strength() const { + return xr_vrs.get_vrs_strength(); +} + +void OpenXRInterface::set_vrs_strength(float p_vrs_strength) { + xr_vrs.set_vrs_strength(p_vrs_strength); +} + double OpenXRInterface::get_render_target_size_multiplier() const { if (openxr_api == nullptr) { return 1.0; @@ -1435,6 +1461,24 @@ Vector3 OpenXRInterface::get_hand_joint_angular_velocity(Hand p_hand, HandJoints return Vector3(); } +RID OpenXRInterface::get_vrs_texture() { + if (!openxr_api) { + return RID(); + } + + PackedVector2Array eye_foci; + + Size2 target_size = get_render_target_size(); + real_t aspect_ratio = target_size.x / target_size.y; + uint32_t view_count = get_view_count(); + + for (uint32_t v = 0; v < view_count; v++) { + eye_foci.push_back(openxr_api->get_eye_focus(v, aspect_ratio)); + } + + return xr_vrs.make_vrs_texture(target_size, eye_foci); +} + OpenXRInterface::OpenXRInterface() { openxr_api = OpenXRAPI::get_singleton(); if (openxr_api) { diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index ac33304757..f0ee0dc3c4 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -80,6 +80,8 @@ private: XRPose::TrackingConfidence head_confidence; Transform3D transform_for_view[2]; // We currently assume 2, but could be 4 for VARJO which we do not support yet + XRVRS xr_vrs; + void _load_action_map(); struct Action { // An action we've registered with OpenXR @@ -168,6 +170,12 @@ public: bool get_foveation_dynamic() const; void set_foveation_dynamic(bool p_foveation_dynamic); + float get_vrs_min_radius() const; + void set_vrs_min_radius(float p_vrs_min_radius); + + float get_vrs_strength() const; + void set_vrs_strength(float p_vrs_strength); + virtual Size2 get_render_target_size() override; virtual uint32_t get_view_count() override; virtual Transform3D get_camera_transform() override; @@ -276,6 +284,8 @@ public: Vector3 get_hand_joint_linear_velocity(Hand p_hand, HandJoints p_joint) const; Vector3 get_hand_joint_angular_velocity(Hand p_hand, HandJoints p_joint) const; + virtual RID get_vrs_texture() override; + OpenXRInterface(); ~OpenXRInterface(); }; |