Browse Source

Expose OpenXR raw hand tracking data

Bastiaan Olij 2 years ago
parent
commit
58df9bd8a4

+ 153 - 0
modules/openxr/doc_classes/OpenXRInterface.xml

@@ -23,6 +23,53 @@
 				Returns display refresh rates supported by the current HMD. Only returned if this feature is supported by the OpenXR runtime and after the interface has been initialized.
 				Returns display refresh rates supported by the current HMD. Only returned if this feature is supported by the OpenXR runtime and after the interface has been initialized.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_hand_joint_angular_velocity" qualifiers="const">
+			<return type="Vector3" />
+			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+			<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
+			<description>
+				If handtracking is enabled, returns the angular velocity of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D]!
+			</description>
+		</method>
+		<method name="get_hand_joint_linear_velocity" qualifiers="const">
+			<return type="Vector3" />
+			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+			<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
+			<description>
+				If handtracking is enabled, returns the linear velocity of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D] without worldscale applied!
+			</description>
+		</method>
+		<method name="get_hand_joint_position" qualifiers="const">
+			<return type="Vector3" />
+			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+			<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
+			<description>
+				If handtracking is enabled, returns the position of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is relative to [XROrigin3D] without worldscale applied!
+			</description>
+		</method>
+		<method name="get_hand_joint_radius" qualifiers="const">
+			<return type="float" />
+			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+			<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
+			<description>
+				If handtracking is enabled, returns the radius of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR. This is without worldscale applied!
+			</description>
+		</method>
+		<method name="get_hand_joint_rotation" qualifiers="const">
+			<return type="Quaternion" />
+			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+			<param index="1" name="joint" type="int" enum="OpenXRInterface.HandJoints" />
+			<description>
+				If handtracking is enabled, returns the rotation of a joint ([param joint]) of a hand ([param hand]) as provided by OpenXR.
+			</description>
+		</method>
+		<method name="get_motion_range" qualifiers="const">
+			<return type="int" enum="OpenXRInterface.HandMotionRange" />
+			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+			<description>
+				If handtracking is enabled and motion range is supported, gets the currently configured motion range for [param hand].
+			</description>
+		</method>
 		<method name="is_action_set_active" qualifiers="const">
 		<method name="is_action_set_active" qualifiers="const">
 			<return type="bool" />
 			<return type="bool" />
 			<param index="0" name="name" type="String" />
 			<param index="0" name="name" type="String" />
@@ -38,6 +85,14 @@
 				Sets the given action set as active or inactive.
 				Sets the given action set as active or inactive.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="set_motion_range">
+			<return type="void" />
+			<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
+			<param index="1" name="motion_range" type="int" enum="OpenXRInterface.HandMotionRange" />
+			<description>
+				If handtracking is enabled and motion range is supported, sets the currently configured motion range for [param hand] to [param motion_range].
+			</description>
+		</method>
 	</methods>
 	</methods>
 	<members>
 	<members>
 		<member name="display_refresh_rate" type="float" setter="set_display_refresh_rate" getter="get_display_refresh_rate" default="0.0">
 		<member name="display_refresh_rate" type="float" setter="set_display_refresh_rate" getter="get_display_refresh_rate" default="0.0">
@@ -74,4 +129,102 @@
 			</description>
 			</description>
 		</signal>
 		</signal>
 	</signals>
 	</signals>
+	<constants>
+		<constant name="HAND_LEFT" value="0" enum="Hand">
+			Left hand.
+		</constant>
+		<constant name="HAND_RIGHT" value="1" enum="Hand">
+			Right hand.
+		</constant>
+		<constant name="HAND_MAX" value="2" enum="Hand">
+			Maximum value for the hand enum.
+		</constant>
+		<constant name="HAND_MOTION_RANGE_UNOBSTRUCTED" value="0" enum="HandMotionRange">
+		</constant>
+		<constant name="HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER" value="1" enum="HandMotionRange">
+		</constant>
+		<constant name="HAND_MOTION_RANGE_MAX" value="2" enum="HandMotionRange">
+		</constant>
+		<constant name="HAND_JOINT_PALM" value="0" enum="HandJoints">
+			Palm joint.
+		</constant>
+		<constant name="HAND_JOINT_WRIST" value="1" enum="HandJoints">
+			Wrist joint.
+		</constant>
+		<constant name="HAND_JOINT_THUMB_METACARPAL" value="2" enum="HandJoints">
+			Thumb metacarpal joint.
+		</constant>
+		<constant name="HAND_JOINT_THUMB_PROXIMAL" value="3" enum="HandJoints">
+			Thumb proximal joint.
+		</constant>
+		<constant name="HAND_JOINT_THUMB_DISTAL" value="4" enum="HandJoints">
+			Thumb distal joint.
+		</constant>
+		<constant name="HAND_JOINT_THUMB_TIP" value="5" enum="HandJoints">
+			Thumb tip joint.
+		</constant>
+		<constant name="HAND_JOINT_INDEX_METACARPAL" value="6" enum="HandJoints">
+			Index metacarpal joint.
+		</constant>
+		<constant name="HAND_JOINT_INDEX_PROXIMAL" value="7" enum="HandJoints">
+			Index proximal joint.
+		</constant>
+		<constant name="HAND_JOINT_INDEX_INTERMEDIATE" value="8" enum="HandJoints">
+			Index intermediate joint.
+		</constant>
+		<constant name="HAND_JOINT_INDEX_DISTAL" value="9" enum="HandJoints">
+			Index distal joint.
+		</constant>
+		<constant name="HAND_JOINT_INDEX_TIP" value="10" enum="HandJoints">
+			Index tip joint.
+		</constant>
+		<constant name="HAND_JOINT_MIDDLE_METACARPAL" value="11" enum="HandJoints">
+			Middle metacarpal joint.
+		</constant>
+		<constant name="HAND_JOINT_MIDDLE_PROXIMAL" value="12" enum="HandJoints">
+			Middle proximal joint.
+		</constant>
+		<constant name="HAND_JOINT_MIDDLE_INTERMEDIATE" value="13" enum="HandJoints">
+			Middle intermediate joint.
+		</constant>
+		<constant name="HAND_JOINT_MIDDLE_DISTAL" value="14" enum="HandJoints">
+			Middle distal joint.
+		</constant>
+		<constant name="HAND_JOINT_MIDDLE_TIP" value="15" enum="HandJoints">
+			Middle tip joint.
+		</constant>
+		<constant name="HAND_JOINT_RING_METACARPAL" value="16" enum="HandJoints">
+			Ring metacarpal joint.
+		</constant>
+		<constant name="HAND_JOINT_RING_PROXIMAL" value="17" enum="HandJoints">
+			Ring proximal joint.
+		</constant>
+		<constant name="HAND_JOINT_RING_INTERMEDIATE" value="18" enum="HandJoints">
+			Ring intermediate joint.
+		</constant>
+		<constant name="HAND_JOINT_RING_DISTAL" value="19" enum="HandJoints">
+			Ring distal joint.
+		</constant>
+		<constant name="HAND_JOINT_RING_TIP" value="20" enum="HandJoints">
+			Ring tip joint.
+		</constant>
+		<constant name="HAND_JOINT_LITTLE_METACARPAL" value="21" enum="HandJoints">
+			Little metacarpal joint.
+		</constant>
+		<constant name="HAND_JOINT_LITTLE_PROXIMAL" value="22" enum="HandJoints">
+			Little proximal joint.
+		</constant>
+		<constant name="HAND_JOINT_LITTLE_INTERMEDIATE" value="23" enum="HandJoints">
+			Little intermediate joint.
+		</constant>
+		<constant name="HAND_JOINT_LITTLE_DISTAL" value="24" enum="HandJoints">
+			Little distal joint.
+		</constant>
+		<constant name="HAND_JOINT_LITTLE_TIP" value="25" enum="HandJoints">
+			Little tip joint.
+		</constant>
+		<constant name="HAND_JOINT_MAX" value="26" enum="HandJoints">
+			Maximum value for the hand joint enum.
+		</constant>
+	</constants>
 </class>
 </class>

+ 59 - 0
modules/openxr/extensions/openxr_hand_tracking_extension.cpp

@@ -276,3 +276,62 @@ void OpenXRHandTrackingExtension::set_motion_range(uint32_t p_hand, XrHandJoints
 	ERR_FAIL_UNSIGNED_INDEX(p_hand, MAX_OPENXR_TRACKED_HANDS);
 	ERR_FAIL_UNSIGNED_INDEX(p_hand, MAX_OPENXR_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 {
+	ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, Quaternion());
+	ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Quaternion());
+
+	if (!hand_trackers[p_hand].is_initialized) {
+		return Quaternion();
+	}
+
+	const XrHandJointLocationEXT &location = hand_trackers[p_hand].joint_locations[p_joint];
+	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 {
+	ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, Vector3());
+	ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
+
+	if (!hand_trackers[p_hand].is_initialized) {
+		return Vector3();
+	}
+
+	const XrHandJointLocationEXT &location = hand_trackers[p_hand].joint_locations[p_joint];
+	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 {
+	ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, 0.0);
+	ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, 0.0);
+
+	if (!hand_trackers[p_hand].is_initialized) {
+		return 0.0;
+	}
+
+	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 {
+	ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, Vector3());
+	ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
+
+	if (!hand_trackers[p_hand].is_initialized) {
+		return Vector3();
+	}
+
+	const XrHandJointVelocityEXT &velocity = hand_trackers[p_hand].joint_velocities[p_joint];
+	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 {
+	ERR_FAIL_UNSIGNED_INDEX_V(p_hand, MAX_OPENXR_TRACKED_HANDS, Vector3());
+	ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, Vector3());
+
+	if (!hand_trackers[p_hand].is_initialized) {
+		return Vector3();
+	}
+
+	const XrHandJointVelocityEXT &velocity = hand_trackers[p_hand].joint_velocities[p_joint];
+	return Vector3(velocity.angularVelocity.x, velocity.angularVelocity.y, velocity.angularVelocity.z);
+}

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

@@ -32,6 +32,7 @@
 #define OPENXR_HAND_TRACKING_EXTENSION_H
 #define OPENXR_HAND_TRACKING_EXTENSION_H
 
 
 #include "../util.h"
 #include "../util.h"
+#include "core/math/quaternion.h"
 #include "openxr_extension_wrapper.h"
 #include "openxr_extension_wrapper.h"
 
 
 #define MAX_OPENXR_TRACKED_HANDS 2
 #define MAX_OPENXR_TRACKED_HANDS 2
@@ -73,6 +74,13 @@ public:
 	XrHandJointsMotionRangeEXT get_motion_range(uint32_t p_hand) const;
 	XrHandJointsMotionRangeEXT get_motion_range(uint32_t p_hand) const;
 	void set_motion_range(uint32_t p_hand, XrHandJointsMotionRangeEXT p_motion_range);
 	void set_motion_range(uint32_t p_hand, XrHandJointsMotionRangeEXT p_motion_range);
 
 
+	Quaternion get_hand_joint_rotation(uint32_t p_hand, XrHandJointEXT p_joint) const;
+	Vector3 get_hand_joint_position(uint32_t p_hand, XrHandJointEXT p_joint) const;
+	float get_hand_joint_radius(uint32_t p_hand, XrHandJointEXT p_joint) const;
+
+	Vector3 get_hand_joint_linear_velocity(uint32_t p_hand, XrHandJointEXT p_joint) const;
+	Vector3 get_hand_joint_angular_velocity(uint32_t p_hand, XrHandJointEXT p_joint) const;
+
 private:
 private:
 	static OpenXRHandTrackingExtension *singleton;
 	static OpenXRHandTrackingExtension *singleton;
 
 

+ 139 - 0
modules/openxr/openxr_interface.cpp

@@ -34,6 +34,8 @@
 #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"
+
 void OpenXRInterface::_bind_methods() {
 void OpenXRInterface::_bind_methods() {
 	// lifecycle signals
 	// lifecycle signals
 	ADD_SIGNAL(MethodInfo("session_begun"));
 	ADD_SIGNAL(MethodInfo("session_begun"));
@@ -57,6 +59,53 @@ void OpenXRInterface::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRInterface::get_action_sets);
 	ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRInterface::get_action_sets);
 
 
 	ClassDB::bind_method(D_METHOD("get_available_display_refresh_rates"), &OpenXRInterface::get_available_display_refresh_rates);
 	ClassDB::bind_method(D_METHOD("get_available_display_refresh_rates"), &OpenXRInterface::get_available_display_refresh_rates);
+
+	// Hand tracking.
+	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_joint_rotation", "hand", "joint"), &OpenXRInterface::get_hand_joint_rotation);
+	ClassDB::bind_method(D_METHOD("get_hand_joint_position", "hand", "joint"), &OpenXRInterface::get_hand_joint_position);
+	ClassDB::bind_method(D_METHOD("get_hand_joint_radius", "hand", "joint"), &OpenXRInterface::get_hand_joint_radius);
+
+	ClassDB::bind_method(D_METHOD("get_hand_joint_linear_velocity", "hand", "joint"), &OpenXRInterface::get_hand_joint_linear_velocity);
+	ClassDB::bind_method(D_METHOD("get_hand_joint_angular_velocity", "hand", "joint"), &OpenXRInterface::get_hand_joint_angular_velocity);
+
+	BIND_ENUM_CONSTANT(HAND_LEFT);
+	BIND_ENUM_CONSTANT(HAND_RIGHT);
+	BIND_ENUM_CONSTANT(HAND_MAX);
+
+	BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_UNOBSTRUCTED);
+	BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER);
+	BIND_ENUM_CONSTANT(HAND_MOTION_RANGE_MAX);
+
+	BIND_ENUM_CONSTANT(HAND_JOINT_PALM);
+	BIND_ENUM_CONSTANT(HAND_JOINT_WRIST);
+	BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_METACARPAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_PROXIMAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_DISTAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_THUMB_TIP);
+	BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_METACARPAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_PROXIMAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_INTERMEDIATE);
+	BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_DISTAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_INDEX_TIP);
+	BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_METACARPAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_PROXIMAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_INTERMEDIATE);
+	BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_DISTAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_MIDDLE_TIP);
+	BIND_ENUM_CONSTANT(HAND_JOINT_RING_METACARPAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_RING_PROXIMAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_RING_INTERMEDIATE);
+	BIND_ENUM_CONSTANT(HAND_JOINT_RING_DISTAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_RING_TIP);
+	BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_METACARPAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_PROXIMAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_INTERMEDIATE);
+	BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_DISTAL);
+	BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_TIP);
+	BIND_ENUM_CONSTANT(HAND_JOINT_MAX);
 }
 }
 
 
 StringName OpenXRInterface::get_name() const {
 StringName OpenXRInterface::get_name() const {
@@ -978,6 +1027,96 @@ void OpenXRInterface::on_pose_recentered() {
 	emit_signal(SNAME("pose_recentered"));
 	emit_signal(SNAME("pose_recentered"));
 }
 }
 
 
+/** Hand tracking. */
+void OpenXRInterface::set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range) {
+	ERR_FAIL_INDEX(p_hand, HAND_MAX);
+	ERR_FAIL_INDEX(p_motion_range, HAND_MOTION_RANGE_MAX);
+
+	OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
+	if (hand_tracking_ext && hand_tracking_ext->get_active()) {
+		XrHandJointsMotionRangeEXT xr_motion_range;
+		switch (p_motion_range) {
+			case HAND_MOTION_RANGE_UNOBSTRUCTED:
+				xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT;
+				break;
+			case HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER:
+				xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT;
+				break;
+			default:
+				// Shouldn't get here, ERR_FAIL_INDEX should have caught this...
+				xr_motion_range = XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT;
+				break;
+		}
+
+		hand_tracking_ext->set_motion_range(uint32_t(p_hand), xr_motion_range);
+	}
+}
+
+OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_hand) const {
+	ERR_FAIL_INDEX_V(p_hand, HAND_MAX, HAND_MOTION_RANGE_MAX);
+
+	OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
+	if (hand_tracking_ext && hand_tracking_ext->get_active()) {
+		XrHandJointsMotionRangeEXT xr_motion_range = hand_tracking_ext->get_motion_range(uint32_t(p_hand));
+
+		switch (xr_motion_range) {
+			case XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT:
+				return HAND_MOTION_RANGE_UNOBSTRUCTED;
+			case XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT:
+				return HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER;
+			default:
+				ERR_FAIL_V_MSG(HAND_MOTION_RANGE_MAX, "Unknown motion range returned by OpenXR");
+		}
+	}
+
+	return HAND_MOTION_RANGE_MAX;
+}
+
+Quaternion OpenXRInterface::get_hand_joint_rotation(Hand p_hand, HandJoints p_joint) const {
+	OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
+	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 Quaternion();
+}
+
+Vector3 OpenXRInterface::get_hand_joint_position(Hand p_hand, HandJoints p_joint) const {
+	OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
+	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 Vector3();
+}
+
+float OpenXRInterface::get_hand_joint_radius(Hand p_hand, HandJoints p_joint) const {
+	OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
+	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 0.0;
+}
+
+Vector3 OpenXRInterface::get_hand_joint_linear_velocity(Hand p_hand, HandJoints p_joint) const {
+	OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
+	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 Vector3();
+}
+
+Vector3 OpenXRInterface::get_hand_joint_angular_velocity(Hand p_hand, HandJoints p_joint) const {
+	OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
+	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 Vector3();
+}
+
 OpenXRInterface::OpenXRInterface() {
 OpenXRInterface::OpenXRInterface() {
 	openxr_api = OpenXRAPI::get_singleton();
 	openxr_api = OpenXRAPI::get_singleton();
 	if (openxr_api) {
 	if (openxr_api) {

+ 57 - 0
modules/openxr/openxr_interface.h

@@ -161,8 +161,65 @@ public:
 	void on_pose_recentered();
 	void on_pose_recentered();
 	void tracker_profile_changed(RID p_tracker, RID p_interaction_profile);
 	void tracker_profile_changed(RID p_tracker, RID p_interaction_profile);
 
 
+	/** Hand tracking. */
+	enum Hand {
+		HAND_LEFT,
+		HAND_RIGHT,
+		HAND_MAX,
+	};
+
+	enum HandMotionRange {
+		HAND_MOTION_RANGE_UNOBSTRUCTED,
+		HAND_MOTION_RANGE_CONFORM_TO_CONTROLLER,
+		HAND_MOTION_RANGE_MAX
+	};
+
+	void set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range);
+	HandMotionRange get_motion_range(const Hand p_hand) const;
+
+	enum HandJoints {
+		HAND_JOINT_PALM = 0,
+		HAND_JOINT_WRIST = 1,
+		HAND_JOINT_THUMB_METACARPAL = 2,
+		HAND_JOINT_THUMB_PROXIMAL = 3,
+		HAND_JOINT_THUMB_DISTAL = 4,
+		HAND_JOINT_THUMB_TIP = 5,
+		HAND_JOINT_INDEX_METACARPAL = 6,
+		HAND_JOINT_INDEX_PROXIMAL = 7,
+		HAND_JOINT_INDEX_INTERMEDIATE = 8,
+		HAND_JOINT_INDEX_DISTAL = 9,
+		HAND_JOINT_INDEX_TIP = 10,
+		HAND_JOINT_MIDDLE_METACARPAL = 11,
+		HAND_JOINT_MIDDLE_PROXIMAL = 12,
+		HAND_JOINT_MIDDLE_INTERMEDIATE = 13,
+		HAND_JOINT_MIDDLE_DISTAL = 14,
+		HAND_JOINT_MIDDLE_TIP = 15,
+		HAND_JOINT_RING_METACARPAL = 16,
+		HAND_JOINT_RING_PROXIMAL = 17,
+		HAND_JOINT_RING_INTERMEDIATE = 18,
+		HAND_JOINT_RING_DISTAL = 19,
+		HAND_JOINT_RING_TIP = 20,
+		HAND_JOINT_LITTLE_METACARPAL = 21,
+		HAND_JOINT_LITTLE_PROXIMAL = 22,
+		HAND_JOINT_LITTLE_INTERMEDIATE = 23,
+		HAND_JOINT_LITTLE_DISTAL = 24,
+		HAND_JOINT_LITTLE_TIP = 25,
+		HAND_JOINT_MAX = 26,
+	};
+
+	Quaternion get_hand_joint_rotation(Hand p_hand, HandJoints p_joint) const;
+	Vector3 get_hand_joint_position(Hand p_hand, HandJoints p_joint) const;
+	float get_hand_joint_radius(Hand p_hand, HandJoints p_joint) const;
+
+	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;
+
 	OpenXRInterface();
 	OpenXRInterface();
 	~OpenXRInterface();
 	~OpenXRInterface();
 };
 };
 
 
+VARIANT_ENUM_CAST(OpenXRInterface::Hand)
+VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange)
+VARIANT_ENUM_CAST(OpenXRInterface::HandJoints)
+
 #endif // OPENXR_INTERFACE_H
 #endif // OPENXR_INTERFACE_H

+ 2 - 2
modules/openxr/scene/openxr_hand.h

@@ -43,13 +43,13 @@ class OpenXRHand : public Node3D {
 	GDCLASS(OpenXRHand, Node3D);
 	GDCLASS(OpenXRHand, Node3D);
 
 
 public:
 public:
-	enum Hands {
+	enum Hands { // Deprecated, need to change this to OpenXRInterface::Hands.
 		HAND_LEFT,
 		HAND_LEFT,
 		HAND_RIGHT,
 		HAND_RIGHT,
 		HAND_MAX
 		HAND_MAX
 	};
 	};
 
 
-	enum MotionRange {
+	enum MotionRange { // Deprecated, need to change this to OpenXRInterface::HandMotionRange.
 		MOTION_RANGE_UNOBSTRUCTED,
 		MOTION_RANGE_UNOBSTRUCTED,
 		MOTION_RANGE_CONFORM_TO_CONTROLLER,
 		MOTION_RANGE_CONFORM_TO_CONTROLLER,
 		MOTION_RANGE_MAX
 		MOTION_RANGE_MAX