Browse Source

OpenXR: Add support for hand tracking source extension

Bastiaan Olij 1 year ago
parent
commit
4c806c03df

+ 22 - 0
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, returns the rotation of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_hand_tracking_source" qualifiers="const">
+			<return type="int" enum="OpenXRInterface.HandTrackedSource" />
+			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+			<description>
+				If handtracking is enabled and hand tracking source is supported, gets the source of the hand tracking data for [param hand].
+			</description>
+		</method>
 		<method name="get_motion_range" qualifiers="const">
 		<method name="get_motion_range" qualifiers="const">
 			<return type="int" enum="OpenXRInterface.HandMotionRange" />
 			<return type="int" enum="OpenXRInterface.HandMotionRange" />
 			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
 			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
@@ -177,10 +184,25 @@
 			Maximum value for the hand enum.
 			Maximum value for the hand enum.
 		</constant>
 		</constant>
 		<constant name="HAND_MOTION_RANGE_UNOBSTRUCTED" value="0" enum="HandMotionRange">
 		<constant name="HAND_MOTION_RANGE_UNOBSTRUCTED" value="0" enum="HandMotionRange">
+			Full hand range, if user closes their hands, we make a full fist.
 		</constant>
 		</constant>
 		<constant name="HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER" value="1" enum="HandMotionRange">
 		<constant name="HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER" value="1" enum="HandMotionRange">
+			Conform to controller, if user closes their hands, the tracked data conforms to the shape of the controller.
 		</constant>
 		</constant>
 		<constant name="HAND_MOTION_RANGE_MAX" value="2" enum="HandMotionRange">
 		<constant name="HAND_MOTION_RANGE_MAX" value="2" enum="HandMotionRange">
+			Maximum value for the motion range enum.
+		</constant>
+		<constant name="HAND_TRACKED_SOURCE_UNKNOWN" value="0" enum="HandTrackedSource">
+			The source of hand tracking data is unknown (the extension is likely unsupported).
+		</constant>
+		<constant name="HAND_TRACKED_SOURCE_UNOBSTRUCTED" value="1" enum="HandTrackedSource">
+			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.
+		</constant>
+		<constant name="HAND_TRACKED_SOURCE_CONTROLLER" value="2" enum="HandTrackedSource">
+			The source of hand tracking is a controller, bone positions are inferred from controller inputs.
+		</constant>
+		<constant name="HAND_TRACKED_SOURCE_MAX" value="3" enum="HandTrackedSource">
+			Maximum value for the hand tracked source enum.
 		</constant>
 		</constant>
 		<constant name="HAND_JOINT_PALM" value="0" enum="HandJoints">
 		<constant name="HAND_JOINT_PALM" value="0" enum="HandJoints">
 			Palm joint.
 			Palm joint.

+ 46 - 11
modules/openxr/extensions/openxr_hand_tracking_extension.cpp

@@ -60,6 +60,7 @@ 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_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME] = &hand_tracking_source_ext;
 
 
 	return request_extensions;
 	return request_extensions;
 }
 }
@@ -137,20 +138,32 @@ void OpenXRHandTrackingExtension::on_process() {
 
 
 	for (int i = 0; i < OPENXR_MAX_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 = {
+			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
 				XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, // type
-				nullptr, // next
+				next_pointer, // next
 				i == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT, // hand
 				i == 0 ? XR_HAND_LEFT_EXT : XR_HAND_RIGHT_EXT, // hand
 				XR_HAND_JOINT_SET_DEFAULT_EXT, // handJointSet
 				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)) {
 			if (XR_FAILED(result)) {
 				// not successful? then we do nothing.
 				// not successful? then we do nothing.
 				print_line("OpenXR: Failed to obtain hand tracking information [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
 				print_line("OpenXR: Failed to obtain hand tracking information [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
 				hand_trackers[i].is_initialized = false;
 				hand_trackers[i].is_initialized = false;
 			} else {
 			} else {
-				void *next_pointer = nullptr;
+				next_pointer = nullptr;
 
 
 				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;
@@ -158,6 +171,14 @@ void OpenXRHandTrackingExtension::on_process() {
 				hand_trackers[i].velocities.jointVelocities = hand_trackers[i].joint_velocities;
 				hand_trackers[i].velocities.jointVelocities = hand_trackers[i].joint_velocities;
 				next_pointer = &hand_trackers[i].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.type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT;
 				hand_trackers[i].locations.next = next_pointer;
 				hand_trackers[i].locations.next = next_pointer;
 				hand_trackers[i].locations.isActive = false;
 				hand_trackers[i].locations.isActive = false;
@@ -171,14 +192,9 @@ void OpenXRHandTrackingExtension::on_process() {
 		if (hand_trackers[i].is_initialized) {
 		if (hand_trackers[i].is_initialized) {
 			void *next_pointer = nullptr;
 			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) {
 			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 = {
 			XrHandJointsLocateInfoEXT locateInfo = {
@@ -240,6 +256,25 @@ XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(HandTra
 	return hand_trackers[p_hand].motion_range;
 	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) {
 void OpenXRHandTrackingExtension::set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range) {
 	ERR_FAIL_UNSIGNED_INDEX(p_hand, OPENXR_MAX_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;

+ 12 - 0
modules/openxr/extensions/openxr_hand_tracking_extension.h

@@ -43,9 +43,17 @@ public:
 		OPENXR_MAX_TRACKED_HANDS
 		OPENXR_MAX_TRACKED_HANDS
 	};
 	};
 
 
+	enum HandTrackedSource {
+		OPENXR_SOURCE_UNKNOWN,
+		OPENXR_SOURCE_UNOBSTRUCTED,
+		OPENXR_SOURCE_CONTROLLER,
+		OPENXR_SOURCE_MAX
+	};
+
 	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;
+		HandTrackedSource source = OPENXR_SOURCE_UNKNOWN;
 
 
 		XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE;
 		XrHandTrackerEXT hand_tracker = XR_NULL_HANDLE;
 		XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT];
 		XrHandJointLocationEXT joint_locations[XR_HAND_JOINT_COUNT_EXT];
@@ -53,6 +61,7 @@ public:
 
 
 		XrHandJointVelocitiesEXT velocities;
 		XrHandJointVelocitiesEXT velocities;
 		XrHandJointLocationsEXT locations;
 		XrHandJointLocationsEXT locations;
+		XrHandTrackingDataSourceStateEXT data_source;
 	};
 	};
 
 
 	static OpenXRHandTrackingExtension *get_singleton();
 	static OpenXRHandTrackingExtension *get_singleton();
@@ -77,6 +86,8 @@ public:
 	XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const;
 	XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const;
 	void set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range);
 	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;
 	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;
 	Quaternion get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;
 	Vector3 get_hand_joint_position(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
 	// 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_source_ext = false;
 
 
 	// functions
 	// functions
 	void cleanup_hand_tracking();
 	void cleanup_hand_tracking();

+ 28 - 0
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("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_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_flags", "hand", "joint"), &OpenXRInterface::get_hand_joint_flags);
 
 
 	ClassDB::bind_method(D_METHOD("get_hand_joint_rotation", "hand", "joint"), &OpenXRInterface::get_hand_joint_rotation);
 	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_CONFORM_TO_CONTROLLER);
 	BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_MAX);
 	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_PALM);
 	BIND_ENUM_CONSTANT(HAND_JOINT_WRIST);
 	BIND_ENUM_CONSTANT(HAND_JOINT_WRIST);
 	BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_METACARPAL);
 	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;
 	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::HandJointFlags> OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const {
 BitField<OpenXRInterface::HandJointFlags> OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const {
 	BitField<OpenXRInterface::HandJointFlags> bits;
 	BitField<OpenXRInterface::HandJointFlags> bits;
 
 

+ 10 - 0
modules/openxr/openxr_interface.h

@@ -194,6 +194,15 @@ public:
 	void set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range);
 	void set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range);
 	HandMotionRange get_motion_range(const Hand p_hand) const;
 	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 {
 	enum HandJoints {
 		HAND_JOINT_PALM = 0,
 		HAND_JOINT_PALM = 0,
 		HAND_JOINT_WRIST = 1,
 		HAND_JOINT_WRIST = 1,
@@ -248,6 +257,7 @@ public:
 
 
 VARIANT_ENUM_CAST(OpenXRInterface::Hand)
 VARIANT_ENUM_CAST(OpenXRInterface::Hand)
 VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange)
 VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange)
+VARIANT_ENUM_CAST(OpenXRInterface::HandTrackedSource)
 VARIANT_ENUM_CAST(OpenXRInterface::HandJoints)
 VARIANT_ENUM_CAST(OpenXRInterface::HandJoints)
 VARIANT_BITFIELD_CAST(OpenXRInterface::HandJointFlags)
 VARIANT_BITFIELD_CAST(OpenXRInterface::HandJointFlags)