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 access to hand joint validity flags #82715

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
36 changes: 36 additions & 0 deletions modules/openxr/doc_classes/OpenXRInterface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
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_flags" qualifiers="const">
<return type="int" enum="OpenXRInterface.HandJointFlags" is_bitfield="true" />
<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 flags that inform us of the validity of the tracking data.
</description>
</method>
<method name="get_hand_joint_linear_velocity" qualifiers="const">
<return type="Vector3" />
<param index="0" name="hand" type="int" enum="OpenXRInterface.Hand" />
Expand Down Expand Up @@ -91,6 +99,13 @@
[b]Note:[/b] This feature is only available on the compatibility renderer and currently only available on some stand alone headsets. For Vulkan set [member Viewport.vrs_mode] to [code]VRS_XR[/code] on desktop.
</description>
</method>
<method name="is_hand_tracking_supported">
<return type="bool" />
<description>
Returns [code]true[/code] if OpenXRs hand tracking is supported and enabled.
[b]Note:[/b] This only returns a valid value after OpenXR has been initialized.
</description>
</method>
<method name="set_action_set_active">
<return type="void" />
<param index="0" name="name" type="String" />
Expand Down Expand Up @@ -246,5 +261,26 @@
<constant name="HAND_JOINT_MAX" value="26" enum="HandJoints">
Maximum value for the hand joint enum.
</constant>
<constant name="HAND_JOINT_NONE" value="0" enum="HandJointFlags" is_bitfield="true">
No flags are set.
</constant>
<constant name="HAND_JOINT_ORIENTATION_VALID" value="1" enum="HandJointFlags" is_bitfield="true">
If set, the orientation data is valid, otherwise, the orientation data is unreliable and should not be used.
</constant>
<constant name="HAND_JOINT_ORIENTATION_TRACKED" value="2" enum="HandJointFlags" is_bitfield="true">
If set, the orientation data comes from tracking data, otherwise, the orientation data contains predicted data.
</constant>
<constant name="HAND_JOINT_POSITION_VALID" value="4" enum="HandJointFlags" is_bitfield="true">
If set, the positional data is valid, otherwise, the positional data is unreliable and should not be used.
</constant>
<constant name="HAND_JOINT_POSITION_TRACKED" value="8" enum="HandJointFlags" is_bitfield="true">
If set, the positional data comes from tracking data, otherwise, the positional data contains predicted data.
</constant>
<constant name="HAND_JOINT_LINEAR_VELOCITY_VALID" value="16" enum="HandJointFlags" is_bitfield="true">
If set, our linear velocity data is valid, otherwise, the linear velocity data is unreliable and should not be used.
</constant>
<constant name="HAND_JOINT_ANGULAR_VELOCITY_VALID" value="32" enum="HandJointFlags" is_bitfield="true">
If set, our angular velocity data is valid, otherwise, the angular velocity data is unreliable and should not be used.
</constant>
</constants>
</class>
24 changes: 24 additions & 0 deletions modules/openxr/extensions/openxr_hand_tracking_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,18 @@ void OpenXRHandTrackingExtension::set_motion_range(HandTrackedHands p_hand, XrHa
hand_trackers[p_hand].motion_range = p_motion_range;
}

XrSpaceLocationFlags OpenXRHandTrackingExtension::get_hand_joint_location_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, XrSpaceLocationFlags(0));
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, XrSpaceLocationFlags(0));

if (!hand_trackers[p_hand].is_initialized) {
return XrSpaceLocationFlags(0);
}

const XrHandJointLocationEXT &location = hand_trackers[p_hand].joint_locations[p_joint];
return location.locationFlags;
}

Quaternion OpenXRHandTrackingExtension::get_hand_joint_rotation(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
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());
Expand Down Expand Up @@ -280,6 +292,18 @@ float OpenXRHandTrackingExtension::get_hand_joint_radius(HandTrackedHands p_hand
return hand_trackers[p_hand].joint_locations[p_joint].radius;
}

XrSpaceVelocityFlags OpenXRHandTrackingExtension::get_hand_joint_velocity_flags(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_hand, OPENXR_MAX_TRACKED_HANDS, XrSpaceVelocityFlags(0));
ERR_FAIL_UNSIGNED_INDEX_V(p_joint, XR_HAND_JOINT_COUNT_EXT, XrSpaceVelocityFlags(0));

if (!hand_trackers[p_hand].is_initialized) {
return XrSpaceVelocityFlags(0);
}

const XrHandJointVelocityEXT &velocity = hand_trackers[p_hand].joint_velocities[p_joint];
return velocity.velocityFlags;
}

Vector3 OpenXRHandTrackingExtension::get_hand_joint_linear_velocity(HandTrackedHands p_hand, XrHandJointEXT p_joint) const {
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());
Expand Down
2 changes: 2 additions & 0 deletions modules/openxr/extensions/openxr_hand_tracking_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,12 @@ class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper {
XrHandJointsMotionRangeEXT get_motion_range(HandTrackedHands p_hand) const;
void set_motion_range(HandTrackedHands p_hand, XrHandJointsMotionRangeEXT p_motion_range);

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;
float get_hand_joint_radius(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;

XrSpaceVelocityFlags get_hand_joint_velocity_flags(HandTrackedHands 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(HandTrackedHands p_hand, XrHandJointEXT p_joint) const;

Expand Down
97 changes: 89 additions & 8 deletions modules/openxr/openxr_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,18 @@ 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_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_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);

ClassDB::bind_method(D_METHOD("is_hand_tracking_supported"), &OpenXRInterface::is_hand_tracking_supported);
ClassDB::bind_method(D_METHOD("is_eye_gaze_interaction_supported"), &OpenXRInterface::is_eye_gaze_interaction_supported);

BIND_ENUM_CONSTANT(HAND_LEFT);
BIND_ENUM_CONSTANT(HAND_RIGHT);
BIND_ENUM_CONSTANT(HAND_MAX);
Expand Down Expand Up @@ -120,7 +125,13 @@ void OpenXRInterface::_bind_methods() {
BIND_ENUM_CONSTANT(HAND_JOINT_LITTLE_TIP);
BIND_ENUM_CONSTANT(HAND_JOINT_MAX);

ClassDB::bind_method(D_METHOD("is_eye_gaze_interaction_supported"), &OpenXRInterface::is_eye_gaze_interaction_supported);
BIND_BITFIELD_FLAG(HAND_JOINT_NONE);
BIND_BITFIELD_FLAG(HAND_JOINT_ORIENTATION_VALID);
BIND_BITFIELD_FLAG(HAND_JOINT_ORIENTATION_TRACKED);
BIND_BITFIELD_FLAG(HAND_JOINT_POSITION_VALID);
BIND_BITFIELD_FLAG(HAND_JOINT_POSITION_TRACKED);
BIND_BITFIELD_FLAG(HAND_JOINT_LINEAR_VELOCITY_VALID);
BIND_BITFIELD_FLAG(HAND_JOINT_ANGULAR_VELOCITY_VALID);
}

StringName OpenXRInterface::get_name() const {
Expand Down Expand Up @@ -709,6 +720,21 @@ Array OpenXRInterface::get_available_display_refresh_rates() const {
}
}

bool OpenXRInterface::is_hand_tracking_supported() {
if (openxr_api == nullptr) {
return false;
} else if (!openxr_api->is_initialized()) {
return false;
} else {
OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext == nullptr) {
return false;
} else {
return hand_tracking_ext->get_active();
}
}
}

bool OpenXRInterface::is_eye_gaze_interaction_supported() {
if (openxr_api == nullptr) {
return false;
Expand Down Expand Up @@ -912,15 +938,39 @@ void OpenXRInterface::handle_hand_tracking(const String &p_path, OpenXRHandTrack
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
XrSpaceLocationFlags location_flags = hand_tracking_ext->get_hand_joint_location_flags(p_hand, XR_HAND_JOINT_PALM_EXT);

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);
if (location_flags & (XR_SPACE_LOCATION_ORIENTATION_VALID_BIT + XR_SPACE_LOCATION_POSITION_VALID_BIT)) {
static const XrSpaceLocationFlags all_location_flags = XR_SPACE_LOCATION_ORIENTATION_VALID_BIT + XR_SPACE_LOCATION_POSITION_VALID_BIT + XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT + XR_SPACE_LOCATION_POSITION_TRACKED_BIT;
XRPose::TrackingConfidence confidence = XRPose::XR_TRACKING_CONFIDENCE_LOW;
Transform3D transform;
Vector3 linear_velocity;
Vector3 angular_velocity;

if ((location_flags & all_location_flags) == all_location_flags) {
// All flags set? confidence is high!
confidence = XRPose::XR_TRACKING_CONFIDENCE_HIGH;
}

tracker->positional_tracker->set_pose("skeleton", transform, linear_velocity, angular_velocity, XRPose::XR_TRACKING_CONFIDENCE_HIGH);
if (location_flags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
transform.basis = Basis(hand_tracking_ext->get_hand_joint_rotation(p_hand, XR_HAND_JOINT_PALM_EXT));
}
if (location_flags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
transform.origin = hand_tracking_ext->get_hand_joint_position(p_hand, XR_HAND_JOINT_PALM_EXT);
}

XrSpaceVelocityFlags velocity_flags = hand_tracking_ext->get_hand_joint_location_flags(p_hand, XR_HAND_JOINT_PALM_EXT);
if (velocity_flags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
linear_velocity = hand_tracking_ext->get_hand_joint_linear_velocity(p_hand, XR_HAND_JOINT_PALM_EXT);
}
if (velocity_flags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
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, confidence);
} else {
tracker->positional_tracker->invalidate_pose("skeleton");
}
}
}
}
Expand Down Expand Up @@ -1183,6 +1233,37 @@ OpenXRInterface::HandMotionRange OpenXRInterface::get_motion_range(const Hand p_
return HAND_MOTION_RANGE_MAX;
}

BitField<OpenXRInterface::HandJointFlags> OpenXRInterface::get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const {
BitField<OpenXRInterface::HandJointFlags> bits;

OpenXRHandTrackingExtension *hand_tracking_ext = OpenXRHandTrackingExtension::get_singleton();
if (hand_tracking_ext && hand_tracking_ext->get_active()) {
XrSpaceLocationFlags location_flags = hand_tracking_ext->get_hand_joint_location_flags(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
if (location_flags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
bits.set_flag(HAND_JOINT_ORIENTATION_VALID);
}
if (location_flags & XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT) {
bits.set_flag(HAND_JOINT_ORIENTATION_TRACKED);
}
if (location_flags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
bits.set_flag(HAND_JOINT_POSITION_VALID);
}
if (location_flags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) {
bits.set_flag(HAND_JOINT_POSITION_TRACKED);
}

XrSpaceVelocityFlags velocity_flags = hand_tracking_ext->get_hand_joint_velocity_flags(OpenXRHandTrackingExtension::HandTrackedHands(p_hand), XrHandJointEXT(p_joint));
if (velocity_flags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
bits.set_flag(HAND_JOINT_LINEAR_VELOCITY_VALID);
}
if (velocity_flags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
bits.set_flag(HAND_JOINT_ANGULAR_VELOCITY_VALID);
}
}

return bits;
}

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()) {
Expand Down
13 changes: 13 additions & 0 deletions modules/openxr/openxr_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class OpenXRInterface : public XRInterface {
virtual PackedStringArray get_suggested_tracker_names() const override;
virtual TrackingStatus get_tracking_status() const override;

bool is_hand_tracking_supported();
bool is_eye_gaze_interaction_supported();

bool initialize_on_startup() const;
Expand Down Expand Up @@ -222,6 +223,17 @@ class OpenXRInterface : public XRInterface {
HAND_JOINT_MAX = 26,
};

enum HandJointFlags {
HAND_JOINT_NONE = 0,
HAND_JOINT_ORIENTATION_VALID = 1,
HAND_JOINT_ORIENTATION_TRACKED = 2,
HAND_JOINT_POSITION_VALID = 4,
HAND_JOINT_POSITION_TRACKED = 8,
HAND_JOINT_LINEAR_VELOCITY_VALID = 16,
HAND_JOINT_ANGULAR_VELOCITY_VALID = 32,
};

BitField<HandJointFlags> get_hand_joint_flags(Hand p_hand, HandJoints p_joint) const;
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;
Expand All @@ -236,5 +248,6 @@ class OpenXRInterface : public XRInterface {
VARIANT_ENUM_CAST(OpenXRInterface::Hand)
VARIANT_ENUM_CAST(OpenXRInterface::HandMotionRange)
VARIANT_ENUM_CAST(OpenXRInterface::HandJoints)
VARIANT_BITFIELD_CAST(OpenXRInterface::HandJointFlags)

#endif // OPENXR_INTERFACE_H
Loading