diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml index 666d20d7e74..caaaeb90ffa 100644 --- a/modules/openxr/doc_classes/OpenXRInterface.xml +++ b/modules/openxr/doc_classes/OpenXRInterface.xml @@ -71,6 +71,13 @@ If handtracking is enabled, returns the rotation of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. + + + + + If handtracking is enabled and hand tracking source is supported, gets the source of the hand tracking data for [param hand]. + + @@ -177,10 +184,25 @@ Maximum value for the hand enum. + Full hand range, if user closes their hands, we make a full fist. + Conform to controller, if user closes their hands, the tracked data conforms to the shape of the controller. + Maximum value for the motion range enum. + + + The source of hand tracking data is unknown (the extension is likely unsupported). + + + The source of hand tracking is unobstructed, this means that an accurate method of hand tracking is used, e.g. optical hand tracking, data gloves, etc. + + + The source of hand tracking is a controller, bone positions are inferred from controller inputs. + + + Maximum value for the hand tracked source enum. Palm joint. diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp index 0d667b56c67..04fc4bf890e 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.cpp +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.cpp @@ -60,6 +60,7 @@ HashMap OpenXRHandTrackingExtension::get_requested_extensions() 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_TRACKING_DATA_SOURCE_EXTENSION_NAME] = &hand_tracking_source_ext; return request_extensions; } @@ -137,20 +138,32 @@ void OpenXRHandTrackingExtension::on_process() { for (int i = 0; i < OPENXR_MAX_TRACKED_HANDS; i++) { if (hand_trackers[i].hand_tracker == XR_NULL_HANDLE) { - XrHandTrackerCreateInfoEXT createInfo = { + void *next_pointer = nullptr; + + // Originally not all XR runtimes supported hand tracking data sourced both from controllers and normal hand tracking. + // With this extension we can indicate we accept input from both sources so hand tracking data is consistently provided + // on runtimes that support this. + XrHandTrackingDataSourceEXT data_sources[2] = { XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT, XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT }; + XrHandTrackingDataSourceInfoEXT data_source_info = { XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT, next_pointer, 2, data_sources }; + if (hand_tracking_source_ext) { + // If supported include this info + next_pointer = &data_source_info; + } + + XrHandTrackerCreateInfoEXT create_info = { XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type - nullptr, // next + next_pointer, // next i == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT, // hand XR_HAND_JOINT_SET_DEFAULT_EXT, // handJointSet }; - result = xrCreateHandTrackerEXT(OpenXRAPI::get_singleton()->get_session(), &createInfo, &hand_trackers[i].hand_tracker); + result = xrCreateHandTrackerEXT(OpenXRAPI::get_singleton()->get_session(), &create_info, &hand_trackers[i].hand_tracker); if (XR_FAILED(result)) { // not successful? then we do nothing. print_line("OpenXR: Failed to obtain hand tracking information [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); hand_trackers[i].is_initialized = false; } else { - void *next_pointer = nullptr; + next_pointer = nullptr; hand_trackers[i].velocities.type = XR_TYPE_HAND_JOINT_VELOCITIES_EXT; hand_trackers[i].velocities.next = next_pointer; @@ -158,6 +171,14 @@ void OpenXRHandTrackingExtension::on_process() { hand_trackers[i].velocities.jointVelocities = hand_trackers[i].joint_velocities; next_pointer = &hand_trackers[i].velocities; + if (hand_tracking_source_ext) { + hand_trackers[i].data_source.type = XR_TYPE_HAND_TRACKING_DATA_SOURCE_STATE_EXT; + hand_trackers[i].data_source.next = next_pointer; + hand_trackers[i].data_source.isActive = false; + hand_trackers[i].data_source.dataSource = XrHandTrackingDataSourceEXT(0); + next_pointer = &hand_trackers[i].data_source; + } + hand_trackers[i].locations.type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT; hand_trackers[i].locations.next = next_pointer; hand_trackers[i].locations.isActive = false; @@ -171,14 +192,9 @@ void OpenXRHandTrackingExtension::on_process() { if (hand_trackers[i].is_initialized) { void *next_pointer = nullptr; - XrHandJointsMotionRangeInfoEXT motionRangeInfo; - + XrHandJointsMotionRangeInfoEXT motion_range_info = { XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, next_pointer, hand_trackers[i].motion_range }; if (hand_motion_range_ext) { - motionRangeInfo.type = XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT; - motionRangeInfo.next = next_pointer; - motionRangeInfo.handJointsMotionRange = hand_trackers[i].motion_range; - - next_pointer = &motionRangeInfo; + next_pointer = &motion_range_info; } XrHandJointsLocateInfoEXT locateInfo = { @@ -240,6 +256,25 @@ XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(HandTra return hand_trackers[p_hand].motion_range; } +OpenXRHandTrackingExtension::HandTrackedSource OpenXRHandTrackingExtension::get_hand_tracking_source(HandTrackedHands p_hand) const { + ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, OPENXR_SOURCE_UNKNOWN); + + if (hand_tracking_source_ext && hand_trackers[p_hand].data_source.isActive) { + switch (hand_trackers[p_hand].data_source.dataSource) { + case XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT: + return OPENXR_SOURCE_UNOBSTRUCTED; + + case XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT: + return OPENXR_SOURCE_CONTROLLER; + + default: + return OPENXR_SOURCE_UNKNOWN; + } + } + + return OPENXR_SOURCE_UNKNOWN; +} + void OpenXRHandTrackingExtension::set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range) { ERR_FAIL_UNSIGNED_INDEX(p_hand, OPENXR_MAX_TRACKED_HANDS); hand_trackers[p_hand].motion_range = p_motion_range; diff --git a/modules/openxr/extensions/openxr_hand_tracking_extension.h b/modules/openxr/extensions/openxr_hand_tracking_extension.h index f9b26fd604a..967538b3777 100644 --- a/modules/openxr/extensions/openxr_hand_tracking_extension.h +++ b/modules/openxr/extensions/openxr_hand_tracking_extension.h @@ -43,9 +43,17 @@ public: OPENXR_MAX_TRACKED_HANDS }; + enum HandTrackedSource { + OPENXR_SOURCE_UNKNOWN, + OPENXR_SOURCE_UNOBSTRUCTED, + OPENXR_SOURCE_CONTROLLER, + OPENXR_SOURCE_MAX + }; + struct HandTracker { bool is_initialized = false; XrHandJointsMotionRangeEXT motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT; + HandTrackedSource source = OPENXR_SOURCE_UNKNOWN; XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE; XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT]; @@ -53,6 +61,7 @@ public: XrHandJointVelocitiesEXT velocities; XrHandJointLocationsEXT locations; + XrHandTrackingDataSourceStateEXT data_source; }; static OpenXRHandTrackingExtension *get_singleton(); @@ -77,6 +86,8 @@ public: XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const; void set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range); + HandTrackedSource get_hand_tracking_source(HandTrackedHands p_hand) const; + XrSpaceLocationFlags get_hand_joint_location_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; Quaternion get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; Vector3 get_hand_joint_position(HandTrackedHands p_hand, XrHandJointEXT p_joint) const; @@ -96,6 +107,7 @@ private: // related extensions bool hand_tracking_ext = false; bool hand_motion_range_ext = false; + bool hand_tracking_source_ext = false; // functions void cleanup_hand_tracking(); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 66f8192c9e0..ceeb1b02782 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -77,6 +77,8 @@ void OpenXRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("set_motion_range", "hand", "motion_range"), &OpenXRInterface::set_motion_range); ClassDB::bind_method(D_METHOD("get_motion_range", "hand"), &OpenXRInterface::get_motion_range); + ClassDB::bind_method(D_METHOD("get_hand_tracking_source", "hand"), &OpenXRInterface::get_hand_tracking_source); + ClassDB::bind_method(D_METHOD("get_hand_joint_flags", "hand", "joint"), &OpenXRInterface::get_hand_joint_flags); ClassDB::bind_method(D_METHOD("get_hand_joint_rotation", "hand", "joint"), &OpenXRInterface::get_hand_joint_rotation); @@ -97,6 +99,11 @@ void OpenXRInterface::_bind_methods() { BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER); BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_MAX); + BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_UNKNOWN); + BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_UNOBSTRUCTED); + BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_CONTROLLER); + BIND_ENUM_CONSTANT(HAND_TRACKED_SOURCE_MAX); + BIND_ENUM_CONSTANT(HAND_JOINT_PALM); BIND_ENUM_CONSTANT(HAND_JOINT_WRIST); BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_METACARPAL); @@ -1269,6 +1276,27 @@ OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_ return HAND_MOTION_RANGE_MAX; } +OpenXRInterface::HandTrackedSource OpenXRInterface::get_hand_tracking_source(const Hand p_hand) const { + ERR_FAIL_INDEX_V(p_hand, HAND_MAX, HAND_TRACKED_SOURCE_UNKNOWN); + + OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton(); + if (hand_tracking_ext && hand_tracking_ext->get_active()) { + OpenXRHandTrackingExtension::HandTrackedSource source = hand_tracking_ext->get_hand_tracking_source(OpenXRHandTrackingExtension::HandTrackedHands(p_hand)); + switch (source) { + case OpenXRHandTrackingExtension::OPENXR_SOURCE_UNOBSTRUCTED: + return HAND_TRACKED_SOURCE_UNOBSTRUCTED; + case OpenXRHandTrackingExtension::OPENXR_SOURCE_CONTROLLER: + return HAND_TRACKED_SOURCE_CONTROLLER; + case OpenXRHandTrackingExtension::OPENXR_SOURCE_UNKNOWN: + return HAND_TRACKED_SOURCE_UNKNOWN; + default: + ERR_FAIL_V_MSG(HAND_TRACKED_SOURCE_UNKNOWN, "Unknown hand tracking source returned by OpenXR"); + } + } + + return HAND_TRACKED_SOURCE_UNKNOWN; +} + BitField OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const { BitField bits; diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h index 489d0845ba5..ca95fdf04df 100644 --- a/modules/openxr/openxr_interface.h +++ b/modules/openxr/openxr_interface.h @@ -194,6 +194,15 @@ public: void set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range); HandMotionRange get_motion_range(const Hand p_hand) const; + enum HandTrackedSource { + HAND_TRACKED_SOURCE_UNKNOWN, + HAND_TRACKED_SOURCE_UNOBSTRUCTED, + HAND_TRACKED_SOURCE_CONTROLLER, + HAND_TRACKED_SOURCE_MAX + }; + + HandTrackedSource get_hand_tracking_source(const Hand p_hand) const; + enum HandJoints { HAND_JOINT_PALM = 0, HAND_JOINT_WRIST = 1, @@ -248,6 +257,7 @@ public: VARIANT_ENUM_CAST(OpenXRInterface::Hand) VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange) +VARIANT_ENUM_CAST(OpenXRInterface::HandTrackedSource) VARIANT_ENUM_CAST(OpenXRInterface::HandJoints) VARIANT_BITFIELD_CAST(OpenXRInterface::HandJointFlags)