summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml8
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp54
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h11
-rw-r--r--modules/openxr/doc_classes/OpenXRInterface.xml8
-rw-r--r--modules/openxr/extensions/openxr_eye_gaze_interaction.cpp36
-rw-r--r--modules/openxr/extensions/openxr_eye_gaze_interaction.h6
-rw-r--r--modules/openxr/openxr_api.cpp85
-rw-r--r--modules/openxr/openxr_api.h4
-rw-r--r--modules/openxr/openxr_interface.cpp44
-rw-r--r--modules/openxr/openxr_interface.h10
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(&current);
- 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(&current);
+ 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(&current);
- 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(&current);
+ 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(&current);
- 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();
};