Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenXR: Add support for hand tracking source extension #85204

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions modules/openxr/doc_classes/OpenXRInterface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
</description>
</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">
<return type="int" enum="OpenXRInterface.HandMotionRange" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
Expand Down Expand Up @@ -177,10 +184,25 @@
Maximum value for the hand enum.
</constant>
<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 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 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 name="HAND_JOINT_PALM" value="0" enum="HandJoints">
Palm joint.
Expand Down
57 changes: 46 additions & 11 deletions modules/openxr/extensions/openxr_hand_tracking_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_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;
}
Expand Down Expand Up @@ -137,27 +138,47 @@ 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;
hand_trackers[i].velocities.jointCount = XR_HAND_JOINT_COUNT_EXT;
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;
Expand All @@ -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 = {
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions modules/openxr/extensions/openxr_hand_tracking_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,25 @@ class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper {
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];
XrHandJointVelocityEXT joint_velocities[XR_HAND_JOINT_COUNT_EXT];

XrHandJointVelocitiesEXT velocities;
XrHandJointLocationsEXT locations;
XrHandTrackingDataSourceStateEXT data_source;
};

static OpenXRHandTrackingExtension *get_singleton();
Expand All @@ -77,6 +86,8 @@ class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper {
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;
Expand All @@ -96,6 +107,7 @@ class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper {
// related extensions
bool hand_tracking_ext = false;
bool hand_motion_range_ext = false;
bool hand_tracking_source_ext = false;

// functions
void cleanup_hand_tracking();
Expand Down
28 changes: 28 additions & 0 deletions modules/openxr/openxr_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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::HandJointFlags> OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const {
BitField<OpenXRInterface::HandJointFlags> bits;

Expand Down
10 changes: 10 additions & 0 deletions modules/openxr/openxr_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ class OpenXRInterface : public XRInterface {
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,
Expand Down Expand Up @@ -248,6 +257,7 @@ class OpenXRInterface : public XRInterface {

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)

Expand Down
Loading