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

Change hand tracking project settings and finetune show_when_tracked #95153

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
15 changes: 12 additions & 3 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2947,10 +2947,19 @@
Specify whether to enable eye tracking for this project. Depending on the platform, additional export configuration may be needed.
</member>
<member name="xr/openxr/extensions/hand_interaction_profile" type="bool" setter="" getter="" default="false">
If true the hand interaction profile extension will be activated if supported by the platform.
If [code]true[/code] the hand interaction profile extension will be activated if supported by the platform.
</member>
<member name="xr/openxr/extensions/hand_tracking" type="bool" setter="" getter="" default="true">
If true we enable the hand tracking extension if available.
<member name="xr/openxr/extensions/hand_tracking" type="bool" setter="" getter="" default="false">
If [code]true[/code], the hand tracking extension is enabled if available.
[b]Note:[/b] By default hand tracking will only work for data sources chosen by the XR runtime. For SteamVR this is the controller inferred data source, for most other runtimes this is the unobstructed data source. There is no way to query this. If a runtime supports the OpenXR data source extension you can use the [member xr/openxr/extensions/hand_tracking_controller_data_source] and/or [member xr/openxr/extensions/hand_tracking_unobstructed_data_source] to indicate you wish to enable these data sources. If neither is selected the data source extension is not enabled and the XR runtimes default behavior persists.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So glad this infuriating bit of nonsense is documented.

</member>
<member name="xr/openxr/extensions/hand_tracking_controller_data_source" type="bool" setter="" getter="" default="false">
If [code]true[/code], support for the controller inferred data source is requested. If supported, you will receive hand tracking data even if the user has a controller in hand, with finger positions automatically inferred from controller input and/or sensors.
[b]Node:[/b] This requires the OpenXR data source extension and controller inferred handtracking to be supported by the XR runtime. If not supported this setting will be ignored. [member xr/openxr/extensions/hand_tracking] must be enabled for this setting to be used.
</member>
<member name="xr/openxr/extensions/hand_tracking_unobstructed_data_source" type="bool" setter="" getter="" default="false">
If [code]true[/code], support for the unobstructed data source is requested. If supported, you will receive hand tracking data based on the actual finger positions of the user often determined by optical tracking.
[b]Node:[/b] This requires the OpenXR data source extension and unobstructed handtracking to be supported by the XR runtime. If not supported this setting will be ignored. [member xr/openxr/extensions/hand_tracking] must be enabled for this setting to be used.
</member>
<member name="xr/openxr/form_factor" type="int" setter="" getter="" default="&quot;0&quot;">
Specify whether OpenXR should be configured for an HMD or a hand held device.
Expand Down
5 changes: 4 additions & 1 deletion doc/classes/XRHandTracker.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,10 @@
<constant name="HAND_TRACKING_SOURCE_CONTROLLER" value="2" enum="HandTrackingSource">
The source of hand tracking data is a controller, meaning that joint positions are inferred from controller inputs.
</constant>
<constant name="HAND_TRACKING_SOURCE_MAX" value="3" enum="HandTrackingSource">
<constant name="HAND_TRACKING_SOURCE_NOT_TRACKED" value="3" enum="HandTrackingSource">
No hand tracking data is tracked, this either means the hand is obscured, the controller is turned off, or tracking is not supported for the current input type.
</constant>
<constant name="HAND_TRACKING_SOURCE_MAX" value="4" enum="HandTrackingSource">
Represents the size of the [enum HandTrackingSource] enum.
</constant>
<constant name="HAND_JOINT_PALM" value="0" enum="HandJoint">
Expand Down
4 changes: 3 additions & 1 deletion main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2512,7 +2512,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true);

// OpenXR project extensions settings.
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking", true);
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_unobstructed_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_controller_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);

Expand Down
77 changes: 51 additions & 26 deletions modules/openxr/extensions/openxr_hand_tracking_extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,14 @@ OpenXRHandTrackingExtension::~OpenXRHandTrackingExtension() {
HashMap<String, bool *> OpenXRHandTrackingExtension::get_requested_extensions() {
HashMap<String, bool *> request_extensions;

unobstructed_data_source = GLOBAL_GET("xr/openxr/extensions/hand_tracking_unobstructed_data_source");
controller_data_source = GLOBAL_GET("xr/openxr/extensions/hand_tracking_controller_data_source");

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;
if (unobstructed_data_source || controller_data_source) {
request_extensions[XR_EXT_HAND_TRACKING_DATA_SOURCE_EXTENSION_NAME] = &hand_tracking_source_ext;
}

return request_extensions;
}
Expand Down Expand Up @@ -141,10 +146,18 @@ void OpenXRHandTrackingExtension::on_process() {
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 };
// With this extension we can indicate we wish to accept input from either or both sources.
// This functionality is subject to the abilities of the XR runtime and requires the data source extension.
// Note: If the data source extension is not available, no guarantees can be made on what the XR runtime supports.
uint32_t data_source_count = 0;
XrHandTrackingDataSourceEXT data_sources[2];
if (unobstructed_data_source) {
data_sources[data_source_count++] = XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT;
}
if (controller_data_source) {
data_sources[data_source_count++] = XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT;
}
XrHandTrackingDataSourceInfoEXT data_source_info = { XR_TYPE_HAND_TRACKING_DATA_SOURCE_INFO_EXT, next_pointer, data_source_count, data_sources };
if (hand_tracking_source_ext) {
// If supported include this info
next_pointer = &data_source_info;
Expand Down Expand Up @@ -224,7 +237,9 @@ void OpenXRHandTrackingExtension::on_process() {
if (XR_FAILED(result)) {
// not successful? then we do nothing.
print_line("OpenXR: Failed to get tracking for hand", i, "[", OpenXRAPI::get_singleton()->get_error_string(result), "]");
godot_tracker->set_hand_tracking_source(XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN);
godot_tracker->set_has_tracking_data(false);
godot_tracker->invalidate_pose("default");
continue;
}

Expand All @@ -235,8 +250,6 @@ void OpenXRHandTrackingExtension::on_process() {
}

if (hand_trackers[i].locations.isActive) {
godot_tracker->set_has_tracking_data(true);

// SKELETON_RIG_HUMANOID bone adjustment. This rotation performs:
// OpenXR Z+ -> Godot Humanoid Y- (Back along the bone)
// OpenXR Y+ -> Godot Humanoid Z- (Out the back of the hand)
Expand All @@ -245,7 +258,6 @@ void OpenXRHandTrackingExtension::on_process() {
for (int joint = 0; joint < XR_HAND_JOINT_COUNT_EXT; joint++) {
const XrHandJointLocationEXT &location = hand_trackers[i].joint_locations[joint];
const XrHandJointVelocityEXT &velocity = hand_trackers[i].joint_velocities[joint];
const XrHandTrackingDataSourceStateEXT &data_source = hand_trackers[i].data_source;
const XrPosef &pose = location.pose;

Transform3D transform;
Expand Down Expand Up @@ -285,23 +297,35 @@ void OpenXRHandTrackingExtension::on_process() {
godot_tracker->set_hand_joint_radius((XRHandTracker::HandJoint)joint, location.radius);

if (joint == XR_HAND_JOINT_PALM_EXT) {
XRHandTracker::HandTrackingSource source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN;
if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_UNOBSTRUCTED;
} else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_CONTROLLER;
}

godot_tracker->set_hand_tracking_source(source);
if (location.locationFlags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT) {
XrHandTrackingDataSourceStateEXT &data_source = hand_trackers[i].data_source;

XRHandTracker::HandTrackingSource source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN;
if (hand_tracking_source_ext) {
if (!data_source.isActive) {
source = XRHandTracker::HAND_TRACKING_SOURCE_NOT_TRACKED;
} else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_UNOBSTRUCTED;
} else if (data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) {
source = XRHandTracker::HAND_TRACKING_SOURCE_CONTROLLER;
} else {
// Data source shouldn't be active, if new data sources are added to OpenXR we need to enable them.
WARN_PRINT_ONCE("Unknown active data source found!");
source = XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN;
}
}
godot_tracker->set_hand_tracking_source(source);
godot_tracker->set_has_tracking_data(true);
godot_tracker->set_pose("default", transform, linear_velocity, angular_velocity);
} else {
godot_tracker->set_hand_tracking_source(hand_tracking_source_ext ? XRHandTracker::HAND_TRACKING_SOURCE_NOT_TRACKED : XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN);
godot_tracker->set_has_tracking_data(false);
godot_tracker->invalidate_pose("default");
}
}
}
} else {
godot_tracker->set_hand_tracking_source(hand_tracking_source_ext ? XRHandTracker::HAND_TRACKING_SOURCE_NOT_TRACKED : XRHandTracker::HAND_TRACKING_SOURCE_UNKNOWN);
godot_tracker->set_has_tracking_data(false);
godot_tracker->invalidate_pose("default");
}
Expand Down Expand Up @@ -349,16 +373,17 @@ XrHandJointsMotionRangeEXT OpenXRHandTrackingExtension::get_motion_range(HandTra
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;
if (hand_tracking_source_ext) {
if (!hand_trackers[p_hand].data_source.isActive) {
return OPENXR_SOURCE_NOT_TRACKED;
} else if (hand_trackers[p_hand].data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT) {
return OPENXR_SOURCE_UNOBSTRUCTED;
} else if (hand_trackers[p_hand].data_source.dataSource == XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT) {
return OPENXR_SOURCE_CONTROLLER;
} else {
// Data source shouldn't be active, if new data sources are added to OpenXR we need to enable them.
WARN_PRINT_ONCE("Unknown active data source found!");
return OPENXR_SOURCE_UNKNOWN;
}
}

Expand Down
3 changes: 3 additions & 0 deletions modules/openxr/extensions/openxr_hand_tracking_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper {
OPENXR_SOURCE_UNKNOWN,
OPENXR_SOURCE_UNOBSTRUCTED,
OPENXR_SOURCE_CONTROLLER,
OPENXR_SOURCE_NOT_TRACKED,
OPENXR_SOURCE_MAX
};

Expand Down Expand Up @@ -110,6 +111,8 @@ class OpenXRHandTrackingExtension : public OpenXRExtensionWrapper {
bool hand_tracking_ext = false;
bool hand_motion_range_ext = false;
bool hand_tracking_source_ext = false;
bool unobstructed_data_source = false;
bool controller_data_source = false;

// functions
void cleanup_hand_tracking();
Expand Down
20 changes: 19 additions & 1 deletion scene/3d/xr_nodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ StringName XRNode3D::get_pose_name() const {

void XRNode3D::set_show_when_tracked(bool p_show) {
show_when_tracked = p_show;

_update_visibility();
}

bool XRNode3D::get_show_when_tracked() const {
Expand Down Expand Up @@ -361,6 +363,9 @@ void XRNode3D::_bind_tracker() {
if (pose.is_valid()) {
set_transform(pose->get_adjusted_transform());
_set_has_tracking_data(pose->get_has_tracking_data());
} else {
// Pose has been invalidated or was never set.
_set_has_tracking_data(false);
}
}
}
Expand Down Expand Up @@ -407,6 +412,10 @@ void XRNode3D::_pose_lost_tracking(const Ref<XRPose> &p_pose) {
}

void XRNode3D::_set_has_tracking_data(bool p_has_tracking_data) {
// Always update our visibility, we may have set our tracking data
// when conditions weren't right.
_update_visibility();

// Ignore if the has_tracking_data state isn't changing.
if (p_has_tracking_data == has_tracking_data) {
return;
Expand All @@ -415,10 +424,19 @@ void XRNode3D::_set_has_tracking_data(bool p_has_tracking_data) {
// Handle change of has_tracking_data.
has_tracking_data = p_has_tracking_data;
emit_signal(SNAME("tracking_changed"), has_tracking_data);
}

void XRNode3D::_update_visibility() {
// If configured, show or hide the node based on tracking data.
if (show_when_tracked) {
set_visible(has_tracking_data);
// Only react to this if we have a primary interface.
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
if (xr_interface.is_valid()) {
set_visible(has_tracking_data);
}
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions scene/3d/xr_nodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ class XRNode3D : public Node3D {
void _pose_lost_tracking(const Ref<XRPose> &p_pose);
void _set_has_tracking_data(bool p_has_tracking_data);

void _update_visibility();

public:
void _validate_property(PropertyInfo &p_property) const;
void set_tracker(const StringName &p_tracker_name);
Expand Down
1 change: 1 addition & 0 deletions servers/xr/xr_hand_tracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ void XRHandTracker::_bind_methods() {
BIND_ENUM_CONSTANT(HAND_TRACKING_SOURCE_UNKNOWN);
BIND_ENUM_CONSTANT(HAND_TRACKING_SOURCE_UNOBSTRUCTED);
BIND_ENUM_CONSTANT(HAND_TRACKING_SOURCE_CONTROLLER);
BIND_ENUM_CONSTANT(HAND_TRACKING_SOURCE_NOT_TRACKED);
BIND_ENUM_CONSTANT(HAND_TRACKING_SOURCE_MAX);

BIND_ENUM_CONSTANT(HAND_JOINT_PALM);
Expand Down
1 change: 1 addition & 0 deletions servers/xr/xr_hand_tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class XRHandTracker : public XRPositionalTracker {
HAND_TRACKING_SOURCE_UNKNOWN,
HAND_TRACKING_SOURCE_UNOBSTRUCTED,
HAND_TRACKING_SOURCE_CONTROLLER,
HAND_TRACKING_SOURCE_NOT_TRACKED,
HAND_TRACKING_SOURCE_MAX
};

Expand Down
Loading