Merge pull request #82722 from BastiaanOlij/openxr_fix_hand_tracking_issues

OpenXR: Fix small hand tracking issues
This commit is contained in:
Rémi Verschelde 2023-10-04 15:43:18 +02:00
commit d7bca20359
No known key found for this signature in database
GPG Key ID: C3336907360768E1
8 changed files with 92 additions and 93 deletions

View File

@ -2728,6 +2728,9 @@
<member name="xr/openxr/extensions/eye_gaze_interaction" type="bool" setter="" getter="" default="false"> <member name="xr/openxr/extensions/eye_gaze_interaction" type="bool" setter="" getter="" default="false">
Specify whether to enable eye tracking for this project. Depending on the platform, additional export configuration may be needed. Specify whether to enable eye tracking for this project. Depending on the platform, additional export configuration may be needed.
</member> </member>
<member name="xr/openxr/extensions/hand_tracking" type="bool" setter="" getter="" default="true">
If true we enable the hand tracking extension if available.
</member>
<member name="xr/openxr/form_factor" type="int" setter="" getter="" default="&quot;0&quot;"> <member name="xr/openxr/form_factor" type="int" setter="" getter="" default="&quot;0&quot;">
Specify whether OpenXR should be configured for an HMD or a hand held device. Specify whether OpenXR should be configured for an HMD or a hand held device.
</member> </member>

View File

@ -2124,7 +2124,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC("xr/openxr/submit_depth_buffer", false); GLOBAL_DEF_BASIC("xr/openxr/submit_depth_buffer", false);
GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true); GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true);
// XR project extensions settings. // OpenXR project extensions settings.
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking", true);
GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false); GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED

View File

@ -32,6 +32,7 @@
#include "../openxr_api.h" #include "../openxr_api.h"
#include "core/config/project_settings.h"
#include "core/string/print_string.h" #include "core/string/print_string.h"
#include "servers/xr_server.h" #include "servers/xr_server.h"
@ -59,7 +60,6 @@ HashMap<String, bool *> OpenXRHandTrackingExtension::get_requested_extensions()
request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext; request_extensions[XR_EXT_HAND_TRACKING_EXTENSION_NAME] = &hand_tracking_ext;
request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext; request_extensions[XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME] = &hand_motion_range_ext;
request_extensions[XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME] = &hand_tracking_aim_state_ext;
return request_extensions; return request_extensions;
} }
@ -106,17 +106,11 @@ void OpenXRHandTrackingExtension::on_state_ready() {
} }
// Setup our hands and reset data // Setup our hands and reset data
for (int i = 0; i < MAX_OPENXR_TRACKED_HANDS; i++) { for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) {
// we'll do this later // we'll do this later
hand_trackers[i].is_initialized = false; hand_trackers[i].is_initialized = false;
hand_trackers[i].hand_tracker = XR_NULL_HANDLE; hand_trackers[i].hand_tracker = XR_NULL_HANDLE;
hand_trackers[i].aimState.aimPose = { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } };
hand_trackers[i].aimState.pinchStrengthIndex = 0.0;
hand_trackers[i].aimState.pinchStrengthMiddle = 0.0;
hand_trackers[i].aimState.pinchStrengthRing = 0.0;
hand_trackers[i].aimState.pinchStrengthLittle = 0.0;
hand_trackers[i].locations.isActive = false; hand_trackers[i].locations.isActive = false;
for (int j = 0; j < XR_HAND_JOINT_COUNT_EXT; j++) { for (int j = 0; j < XR_HAND_JOINT_COUNT_EXT; j++) {
@ -141,7 +135,7 @@ void OpenXRHandTrackingExtension::on_process() {
XrResult result; XrResult result;
for (int i = 0; i < MAX_OPENXR_TRACKED_HANDS; i++) { for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) {
if (hand_trackers[i].hand_tracker == XR_NULL_HANDLE) { if (hand_trackers[i].hand_tracker == XR_NULL_HANDLE) {
XrHandTrackerCreateInfoEXT createInfo = { XrHandTrackerCreateInfoEXT createInfo = {
XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type
@ -157,18 +151,6 @@ void OpenXRHandTrackingExtension::on_process() {
hand_trackers[i].is_initialized = false; hand_trackers[i].is_initialized = false;
} else { } else {
void *next_pointer = nullptr; void *next_pointer = nullptr;
if (hand_tracking_aim_state_ext) {
hand_trackers[i].aimState.type = XR_TYPE_HAND_TRACKING_AIM_STATE_FB;
hand_trackers[i].aimState.next = next_pointer;
hand_trackers[i].aimState.status = 0;
hand_trackers[i].aimState.aimPose = { { 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } };
hand_trackers[i].aimState.pinchStrengthIndex = 0.0;
hand_trackers[i].aimState.pinchStrengthMiddle = 0.0;
hand_trackers[i].aimState.pinchStrengthRing = 0.0;
hand_trackers[i].aimState.pinchStrengthLittle = 0.0;
next_pointer = &hand_trackers[i].aimState;
}
hand_trackers[i].velocities.type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT; hand_trackers[i].velocities.type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT;
hand_trackers[i].velocities.next = next_pointer; hand_trackers[i].velocities.next = next_pointer;
@ -219,20 +201,6 @@ void OpenXRHandTrackingExtension::on_process() {
!hand_trackers[i].locations.isActive || isnan(palm.position.x) || palm.position.x < -1000000.00 || palm.position.x > 1000000.00) { !hand_trackers[i].locations.isActive || isnan(palm.position.x) || palm.position.x < -1000000.00 || palm.position.x > 1000000.00) {
hand_trackers[i].locations.isActive = false; // workaround, make sure its inactive hand_trackers[i].locations.isActive = false; // workaround, make sure its inactive
} }
/* TODO change this to managing the controller from openxr_interface
if (hand_tracking_aim_state_ext && hand_trackers[i].locations.isActive && check_bit(XR_HAND_TRACKING_AIM_VALID_BIT_FB, hand_trackers[i].aimState.status)) {
// Controllers are updated based on the aim state's pose and pinches' strength
if (hand_trackers[i].aim_state_godot_controller == -1) {
hand_trackers[i].aim_state_godot_controller =
arvr_api->godot_arvr_add_controller(
const_cast<char *>(hand_controller_names[i]),
i + HAND_CONTROLLER_ID_OFFSET,
true,
true);
}
}
*/
} }
} }
} }
@ -246,7 +214,7 @@ void OpenXRHandTrackingExtension::cleanup_hand_tracking() {
XRServer *xr_server = XRServer::get_singleton(); XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server); ERR_FAIL_NULL(xr_server);
for (int i = 0; i < MAX_OPENXR_TRACKED_HANDS; i++) { for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) {
if (hand_trackers[i].hand_tracker != XR_NULL_HANDLE) { if (hand_trackers[i].hand_tracker != XR_NULL_HANDLE) {
xrDestroyHandTrackerEXT(hand_trackers[i].hand_tracker); xrDestroyHandTrackerEXT(hand_trackers[i].hand_tracker);
@ -260,25 +228,25 @@ bool OpenXRHandTrackingExtension::get_active() {
return handTrackingSystemProperties.supportsHandTracking; return handTrackingSystemProperties.supportsHandTracking;
} }
const OpenXRHandTrackingExtension::HandTracker *OpenXRHandTrackingExtension::get_hand_tracker(uint32_t p_hand) const { const OpenXRHandTrackingExtension::HandTracker *OpenXRHandTrackingExtension::get_hand_tracker(HandTrackedHands p_hand) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, nullptr); ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, nullptr);
return &hand_trackers[p_hand]; return &hand_trackers[p_hand];
} }
XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(uint32_t p_hand) const { XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(HandTrackedHands p_hand) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT); ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT);
return hand_trackers[p_hand].motion_range; return hand_trackers[p_hand].motion_range;
} }
void OpenXRHandTrackingExtension::set_motion_range(uint32_t p_hand, XrHandJointsMotionRangeEXT p_motion_range) { void OpenXRHandTrackingExtension::set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range) {
ERR_FAIL_UNSIGNED_INDEX(p_hand, MAX_OPENXR_TRACKED_HANDS); ERR_FAIL_UNSIGNED_INDEX(p_hand, OPENXR_MAX_TRACKED_HANDS);
hand_trackers[p_hand].motion_range = p_motion_range; hand_trackers[p_hand].motion_range = p_motion_range;
} }
Quaternion OpenXRHandTrackingExtension::get_hand_joint_rotation(uint32_t p_hand, XrHandJointEXT p_joint) const { Quaternion OpenXRHandTrackingExtension::get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, Quaternion()); ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Quaternion());
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Quaternion()); ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Quaternion());
if (!hand_trackers[p_hand].is_initialized) { if (!hand_trackers[p_hand].is_initialized) {
@ -289,8 +257,8 @@ Quaternion OpenXRHandTrackingExtension::get_hand_joint_rotation(uint32_t p_hand,
return Quaternion(location.pose.orientation.x, location.pose.orientation.y, location.pose.orientation.z, location.pose.orientation.w); return Quaternion(location.pose.orientation.x, location.pose.orientation.y, location.pose.orientation.z, location.pose.orientation.w);
} }
Vector3 OpenXRHandTrackingExtension::get_hand_joint_position(uint32_t p_hand, XrHandJointEXT p_joint) const { Vector3 OpenXRHandTrackingExtension::get_hand_joint_position(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, Vector3()); ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Vector3());
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3()); ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
if (!hand_trackers[p_hand].is_initialized) { if (!hand_trackers[p_hand].is_initialized) {
@ -301,8 +269,8 @@ Vector3 OpenXRHandTrackingExtension::get_hand_joint_position(uint32_t p_hand, Xr
return Vector3(location.pose.position.x, location.pose.position.y, location.pose.position.z); return Vector3(location.pose.position.x, location.pose.position.y, location.pose.position.z);
} }
float OpenXRHandTrackingExtension::get_hand_joint_radius(uint32_t p_hand, XrHandJointEXT p_joint) const { float OpenXRHandTrackingExtension::get_hand_joint_radius(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, 0.0); ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, 0.0);
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, 0.0); ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, 0.0);
if (!hand_trackers[p_hand].is_initialized) { if (!hand_trackers[p_hand].is_initialized) {
@ -312,8 +280,8 @@ float OpenXRHandTrackingExtension::get_hand_joint_radius(uint32_t p_hand, XrHand
return hand_trackers[p_hand].joint_locations[p_joint].radius; return hand_trackers[p_hand].joint_locations[p_joint].radius;
} }
Vector3 OpenXRHandTrackingExtension::get_hand_joint_linear_velocity(uint32_t p_hand, XrHandJointEXT p_joint) const { Vector3 OpenXRHandTrackingExtension::get_hand_joint_linear_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, Vector3()); ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Vector3());
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3()); ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
if (!hand_trackers[p_hand].is_initialized) { if (!hand_trackers[p_hand].is_initialized) {
@ -324,8 +292,8 @@ Vector3 OpenXRHandTrackingExtension::get_hand_joint_linear_velocity(uint32_t p_h
return Vector3(velocity.linearVelocity.x, velocity.linearVelocity.y, velocity.linearVelocity.z); return Vector3(velocity.linearVelocity.x, velocity.linearVelocity.y, velocity.linearVelocity.z);
} }
Vector3 OpenXRHandTrackingExtension::get_hand_joint_angular_velocity(uint32_t p_hand, XrHandJointEXT p_joint) const { Vector3 OpenXRHandTrackingExtension::get_hand_joint_angular_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, Vector3()); ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, Vector3());
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3()); ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
if (!hand_trackers[p_hand].is_initialized) { if (!hand_trackers[p_hand].is_initialized) {

View File

@ -35,10 +35,14 @@
#include "core/math/quaternion.h" #include "core/math/quaternion.h"
#include "openxr_extension_wrapper.h" #include "openxr_extension_wrapper.h"
#define MAX_OPENXR_TRACKED_HANDS 2
class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper { class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper {
public: public:
enum HandTrackedHands {
OPENXR_TRACKED_LEFT_HAND,
OPENXR_TRACKED_RIGHT_HAND,
OPENXR_MAX_TRACKED_HANDS
};
struct HandTracker { struct HandTracker {
bool is_initialized = false; bool is_initialized = false;
XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT; XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT;
@ -47,7 +51,6 @@ public:
XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT]; XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT];
XrHandJointVelocityEXT joint_velocities[XR_HAND_JOINT_COUNT_EXT]; XrHandJointVelocityEXT joint_velocities[XR_HAND_JOINT_COUNT_EXT];
XrHandTrackingAimStateFB aimState;
XrHandJointVelocitiesEXT velocities; XrHandJointVelocitiesEXT velocities;
XrHandJointLocationsEXT locations; XrHandJointLocationsEXT locations;
}; };
@ -69,29 +72,28 @@ public:
virtual void on_state_stopping() override; virtual void on_state_stopping() override;
bool get_active(); bool get_active();
const HandTracker *get_hand_tracker(uint32_t p_hand) const; const HandTracker *get_hand_tracker(HandTrackedHands p_hand) const;
XrHandJointsMotionRangeEXT get_motion_range(uint32_t p_hand) const; XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const;
void set_motion_range(uint32_t p_hand, XrHandJointsMotionRangeEXT p_motion_range); void set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range);
Quaternion get_hand_joint_rotation(uint32_t p_hand, XrHandJointEXT p_joint) const; Quaternion get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
Vector3 get_hand_joint_position(uint32_t p_hand, XrHandJointEXT p_joint) const; Vector3 get_hand_joint_position(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
float get_hand_joint_radius(uint32_t p_hand, XrHandJointEXT p_joint) const; float get_hand_joint_radius(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
Vector3 get_hand_joint_linear_velocity(uint32_t p_hand, XrHandJointEXT p_joint) const; Vector3 get_hand_joint_linear_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
Vector3 get_hand_joint_angular_velocity(uint32_t p_hand, XrHandJointEXT p_joint) const; Vector3 get_hand_joint_angular_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
private: private:
static OpenXRHandTrackingExtension *singleton; static OpenXRHandTrackingExtension *singleton;
// state // state
XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties; XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties;
HandTracker hand_trackers[MAX_OPENXR_TRACKED_HANDS]; // Fixed for left and right hand HandTracker hand_trackers[OPENXR_MAX_TRACKED_HANDS]; // Fixed for left and right hand
// related extensions // related extensions
bool hand_tracking_ext = false; bool hand_tracking_ext = false;
bool hand_motion_range_ext = false; bool hand_motion_range_ext = false;
bool hand_tracking_aim_state_ext = false;
// functions // functions
void cleanup_hand_tracking(); void cleanup_hand_tracking();

View File

@ -34,8 +34,6 @@
#include "core/io/resource_saver.h" #include "core/io/resource_saver.h"
#include "servers/rendering/rendering_server_globals.h" #include "servers/rendering/rendering_server_globals.h"
#include "extensions/openxr_hand_tracking_extension.h"
#include "extensions/openxr_eye_gaze_interaction.h" #include "extensions/openxr_eye_gaze_interaction.h"
void OpenXRInterface::_bind_methods() { void OpenXRInterface::_bind_methods() {
@ -909,6 +907,24 @@ RID OpenXRInterface::get_depth_texture() {
} }
} }
void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrackingExtension::HandTrackedHands p_hand) {
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
OpenXRInterface::Tracker *tracker = find_tracker(p_path);
if (tracker && tracker->positional_tracker.is_valid()) {
// TODO add in confidence! Requires PR #82715
Transform3D transform;
transform.basis = Basis(hand_tracking_ext->get_hand_joint_rotation(p_hand, XR_HAND_JOINT_PALM_EXT));
transform.origin = hand_tracking_ext->get_hand_joint_position(p_hand, XR_HAND_JOINT_PALM_EXT);
Vector3 linear_velocity = hand_tracking_ext->get_hand_joint_linear_velocity(p_hand, XR_HAND_JOINT_PALM_EXT);
Vector3 angular_velocity = hand_tracking_ext->get_hand_joint_angular_velocity(p_hand, XR_HAND_JOINT_PALM_EXT);
tracker->positional_tracker->set_pose("skeleton", transform, linear_velocity, angular_velocity, XRPose::XR_TRACKING_CONFIDENCE_HIGH);
}
}
}
void OpenXRInterface::process() { void OpenXRInterface::process() {
if (openxr_api) { if (openxr_api) {
// do our normal process // do our normal process
@ -916,8 +932,8 @@ void OpenXRInterface::process() {
Transform3D t; Transform3D t;
Vector3 linear_velocity; Vector3 linear_velocity;
Vector3 angular_velocity; Vector3 angular_velocity;
XRPose::TrackingConfidence confidence = openxr_api->get_head_center(t, linear_velocity, angular_velocity); head_confidence = openxr_api->get_head_center(t, linear_velocity, angular_velocity);
if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) { if (head_confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) {
// Only update our transform if we have one to update it with // Only update our transform if we have one to update it with
// note that poses are stored without world scale and reference frame applied! // note that poses are stored without world scale and reference frame applied!
head_transform = t; head_transform = t;
@ -939,14 +955,14 @@ void OpenXRInterface::process() {
handle_tracker(trackers[i]); handle_tracker(trackers[i]);
} }
} }
// Handle hand tracking
handle_hand_tracking("/user/hand/left", OpenXRHandTrackingExtension::OPENXR_TRACKED_LEFT_HAND);
handle_hand_tracking("/user/hand/right", OpenXRHandTrackingExtension::OPENXR_TRACKED_RIGHT_HAND);
} }
if (head.is_valid()) { if (head.is_valid()) {
// TODO figure out how to get our velocities head->set_pose("default", head_transform, head_linear_velocity, head_angular_velocity, head_confidence);
head->set_pose("default", head_transform, head_linear_velocity, head_angular_velocity);
// TODO set confidence on pose once we support tracking this..
} }
} }
@ -1143,7 +1159,7 @@ void OpenXRInterface::set_motion_range(const Hand p_hand, const HandMotionRange
break; break;
} }
hand_tracking_ext->set_motion_range(uint32_t(p_hand), xr_motion_range); hand_tracking_ext->set_motion_range(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), xr_motion_range);
} }
} }
@ -1152,7 +1168,7 @@ OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) { if (hand_tracking_ext && hand_tracking_ext->get_active()) {
XrHandJointsMotionRangeEXT xr_motion_range = hand_tracking_ext->get_motion_range(uint32_t(p_hand)); XrHandJointsMotionRangeEXT xr_motion_range = hand_tracking_ext->get_motion_range(OpenXRHandTrackingExtension::HandTrackedHands(p_hand));
switch (xr_motion_range) { switch (xr_motion_range) {
case XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT: case XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT:
@ -1170,7 +1186,7 @@ OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_
Quaternion OpenXRInterface::get_hand_joint_rotation(Hand p_hand, HandJoints p_joint) const { Quaternion OpenXRInterface::get_hand_joint_rotation(Hand p_hand, HandJoints p_joint) const {
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) { if (hand_tracking_ext && hand_tracking_ext->get_active()) {
return hand_tracking_ext->get_hand_joint_rotation(uint32_t(p_hand), XrHandJointEXT(p_joint)); return hand_tracking_ext->get_hand_joint_rotation(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
} }
return Quaternion(); return Quaternion();
@ -1179,7 +1195,7 @@ Quaternion OpenXRInterface::get_hand_joint_rotation(Hand p_hand, HandJoints p_jo
Vector3 OpenXRInterface::get_hand_joint_position(Hand p_hand, HandJoints p_joint) const { Vector3 OpenXRInterface::get_hand_joint_position(Hand p_hand, HandJoints p_joint) const {
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) { if (hand_tracking_ext && hand_tracking_ext->get_active()) {
return hand_tracking_ext->get_hand_joint_position(uint32_t(p_hand), XrHandJointEXT(p_joint)); return hand_tracking_ext->get_hand_joint_position(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
} }
return Vector3(); return Vector3();
@ -1188,7 +1204,7 @@ Vector3 OpenXRInterface::get_hand_joint_position(Hand p_hand, HandJoints p_joint
float OpenXRInterface::get_hand_joint_radius(Hand p_hand, HandJoints p_joint) const { float OpenXRInterface::get_hand_joint_radius(Hand p_hand, HandJoints p_joint) const {
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) { if (hand_tracking_ext && hand_tracking_ext->get_active()) {
return hand_tracking_ext->get_hand_joint_radius(uint32_t(p_hand), XrHandJointEXT(p_joint)); return hand_tracking_ext->get_hand_joint_radius(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
} }
return 0.0; return 0.0;
@ -1197,7 +1213,7 @@ float OpenXRInterface::get_hand_joint_radius(Hand p_hand, HandJoints p_joint) co
Vector3 OpenXRInterface::get_hand_joint_linear_velocity(Hand p_hand, HandJoints p_joint) const { Vector3 OpenXRInterface::get_hand_joint_linear_velocity(Hand p_hand, HandJoints p_joint) const {
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) { if (hand_tracking_ext && hand_tracking_ext->get_active()) {
return hand_tracking_ext->get_hand_joint_linear_velocity(uint32_t(p_hand), XrHandJointEXT(p_joint)); return hand_tracking_ext->get_hand_joint_linear_velocity(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
} }
return Vector3(); return Vector3();
@ -1206,7 +1222,7 @@ Vector3 OpenXRInterface::get_hand_joint_linear_velocity(Hand p_hand, HandJoints
Vector3 OpenXRInterface::get_hand_joint_angular_velocity(Hand p_hand, HandJoints p_joint) const { Vector3 OpenXRInterface::get_hand_joint_angular_velocity(Hand p_hand, HandJoints p_joint) const {
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) { if (hand_tracking_ext && hand_tracking_ext->get_active()) {
return hand_tracking_ext->get_hand_joint_angular_velocity(uint32_t(p_hand), XrHandJointEXT(p_joint)); return hand_tracking_ext->get_hand_joint_angular_velocity(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
} }
return Vector3(); return Vector3();

View File

@ -33,6 +33,7 @@
#include "action_map/openxr_action_map.h" #include "action_map/openxr_action_map.h"
#include "extensions/openxr_fb_passthrough_extension_wrapper.h" #include "extensions/openxr_fb_passthrough_extension_wrapper.h"
#include "extensions/openxr_hand_tracking_extension.h"
#include "openxr_api.h" #include "openxr_api.h"
#include "servers/xr/xr_interface.h" #include "servers/xr/xr_interface.h"
@ -55,6 +56,7 @@ private:
Transform3D head_transform; Transform3D head_transform;
Vector3 head_linear_velocity; Vector3 head_linear_velocity;
Vector3 head_angular_velocity; Vector3 head_angular_velocity;
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 Transform3D transform_for_view[2]; // We currently assume 2, but could be 4 for VARJO which we do not support yet
void _load_action_map(); void _load_action_map();
@ -97,6 +99,8 @@ private:
void _set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye); void _set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye);
void handle_hand_tracking(const String &p_path, OpenXRHandTrackingExtension::HandTrackedHands p_hand);
protected: protected:
static void _bind_methods(); static void _bind_methods();

View File

@ -105,20 +105,24 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
#endif #endif
// register our other extensions // register our other extensions
if (GLOBAL_GET("xr/openxr/extensions/eye_gaze_interaction") && (!OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME))) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXREyeGazeInteractionExtension));
}
OpenXRAPI::register_extension_wrapper(memnew(OpenXRPalmPoseExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRPalmPoseExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRPicoControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRPicoControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHuaweiControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRHuaweiControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHandTrackingExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRWMRControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRWMRControllerExtension));
OpenXRAPI::register_extension_wrapper(memnew(OpenXRML2ControllerExtension)); OpenXRAPI::register_extension_wrapper(memnew(OpenXRML2ControllerExtension));
// register gated extensions
if (GLOBAL_GET("xr/openxr/extensions/eye_gaze_interaction") && (!OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME))) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXREyeGazeInteractionExtension));
}
if (GLOBAL_GET("xr/openxr/extensions/hand_tracking")) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHandTrackingExtension));
}
} }
if (OpenXRAPI::openxr_is_enabled()) { if (OpenXRAPI::openxr_is_enabled()) {

View File

@ -113,7 +113,7 @@ void OpenXRHand::_set_motion_range() {
break; break;
} }
hand_tracking_ext->set_motion_range(hand, xr_motion_range); hand_tracking_ext->set_motion_range(OpenXRHandTrackingExtension::HandTrackedHands(hand), xr_motion_range);
} }
Skeleton3D *OpenXRHand::get_skeleton() { Skeleton3D *OpenXRHand::get_skeleton() {
@ -204,7 +204,7 @@ void OpenXRHand::_update_skeleton() {
Quaternion inv_quaternions[XR_HAND_JOINT_COUNT_EXT]; Quaternion inv_quaternions[XR_HAND_JOINT_COUNT_EXT];
Vector3 positions[XR_HAND_JOINT_COUNT_EXT]; Vector3 positions[XR_HAND_JOINT_COUNT_EXT];
const OpenXRHandTrackingExtension::HandTracker *hand_tracker = hand_tracking_ext->get_hand_tracker(hand); const OpenXRHandTrackingExtension::HandTracker *hand_tracker = hand_tracking_ext->get_hand_tracker(OpenXRHandTrackingExtension::HandTrackedHands(hand));
const float ws = XRServer::get_singleton()->get_world_scale(); const float ws = XRServer::get_singleton()->get_world_scale();
if (hand_tracker->is_initialized && hand_tracker->locations.isActive) { if (hand_tracker->is_initialized && hand_tracker->locations.isActive) {
@ -243,26 +243,27 @@ void OpenXRHand::_update_skeleton() {
// Get our target quaternion // Get our target quaternion
Quaternion q = quaternions[i]; Quaternion q = quaternions[i];
// Get our target position
Vector3 p = positions[i];
// get local translation, parent should already be processed // get local translation, parent should already be processed
if (parent == -1) { if (parent == -1) {
// use our palm location here, that is what we are tracking // use our palm location here, that is what we are tracking
q = inv_quaternions[XR_HAND_JOINT_PALM_EXT] * q; q = inv_quaternions[XR_HAND_JOINT_PALM_EXT] * q;
p = inv_quaternions[XR_HAND_JOINT_PALM_EXT].xform(p - positions[XR_HAND_JOINT_PALM_EXT]);
} else { } else {
int found = false; int found = false;
for (int b = 0; b < XR_HAND_JOINT_COUNT_EXT && !found; b++) { for (int b = 0; b < XR_HAND_JOINT_COUNT_EXT && !found; b++) {
if (bones[b] == parent) { if (bones[b] == parent) {
q = inv_quaternions[b] * q; q = inv_quaternions[b] * q;
p = inv_quaternions[b].xform(p - positions[b]);
found = true; found = true;
} }
} }
} }
// And get the movement from our rest position
// Transform3D rest = skeleton->get_bone_rest(bones[i]);
// q = rest.basis.get_quaternion().inverse() * q;
// and set our pose // and set our pose
// skeleton->set_bone_pose_position(bones[i], v); skeleton->set_bone_pose_position(bones[i], p);
skeleton->set_bone_pose_rotation(bones[i], q); skeleton->set_bone_pose_rotation(bones[i], q);
} }
} }