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

WebXR: Add support for hand tracking #88411

Merged
merged 1 commit into from
Feb 23, 2024
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
4 changes: 4 additions & 0 deletions modules/webxr/doc_classes/WebXRInterface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@
</method>
</methods>
<members>
<member name="enabled_features" type="String" setter="" getter="get_enabled_features">
A comma-separated list of features that were successfully enabled by [method XRInterface.initialize] when setting up the WebXR session.
This may include features requested by setting [member required_features] and [member optional_features].
</member>
<member name="optional_features" type="String" setter="set_optional_features" getter="get_optional_features">
A comma-seperated list of optional features used by [method XRInterface.initialize] when setting up the WebXR session.
If a user's browser or device doesn't support one of the given features, initialization will continue, but you won't be able to use the requested feature.
Expand Down
7 changes: 5 additions & 2 deletions modules/webxr/godot_webxr.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ enum WebXRInputEvent {
};

typedef void (*GodotWebXRSupportedCallback)(char *p_session_mode, int p_supported);
typedef void (*GodotWebXRStartedCallback)(char *p_reference_space_type);
typedef void (*GodotWebXRStartedCallback)(char *p_reference_space_type, char *p_enabled_features);
typedef void (*GodotWebXREndedCallback)();
typedef void (*GodotWebXRFailedCallback)(char *p_message);
typedef void (*GodotWebXRInputEventCallback)(int p_event_type, int p_input_source_id);
Expand Down Expand Up @@ -85,7 +85,10 @@ extern bool godot_webxr_update_input_source(
int *r_button_count,
float *r_buttons,
int *r_axes_count,
float *r_axes);
float *r_axes,
int *r_has_hand_data,
float *r_hand_joints,
float *r_hand_radii);

extern char *godot_webxr_get_visibility_state();
extern int godot_webxr_get_bounds_geometry(float **r_points);
Expand Down
25 changes: 20 additions & 5 deletions modules/webxr/native/library_godot_webxr.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,11 @@ const GodotWebXR = {
// callback don't bubble up here and cause Godot to try the
// next reference space.
window.setTimeout(function () {
const c_str = GodotRuntime.allocString(reference_space_type);
onstarted(c_str);
GodotRuntime.free(c_str);
const reference_space_c_str = GodotRuntime.allocString(reference_space_type);
const enabled_features_c_str = GodotRuntime.allocString(Array.from(session.enabledFeatures).join(","));
onstarted(reference_space_c_str, enabled_features_c_str);
GodotRuntime.free(reference_space_c_str);
GodotRuntime.free(enabled_features_c_str);
}, 0);
}

Expand Down Expand Up @@ -479,8 +481,8 @@ const GodotWebXR = {
},

godot_webxr_update_input_source__proxy: 'sync',
godot_webxr_update_input_source__sig: 'iiiiiiiiiiii',
godot_webxr_update_input_source: function (p_input_source_id, r_target_pose, r_target_ray_mode, r_touch_index, r_has_grip_pose, r_grip_pose, r_has_standard_mapping, r_button_count, r_buttons, r_axes_count, r_axes) {
godot_webxr_update_input_source__sig: 'iiiiiiiiiiiiiii',
godot_webxr_update_input_source: function (p_input_source_id, r_target_pose, r_target_ray_mode, r_touch_index, r_has_grip_pose, r_grip_pose, r_has_standard_mapping, r_button_count, r_buttons, r_axes_count, r_axes, r_has_hand_data, r_hand_joints, r_hand_radii) {
if (!GodotWebXR.session || !GodotWebXR.frame) {
return 0;
}
Expand Down Expand Up @@ -563,6 +565,19 @@ const GodotWebXR = {
GodotRuntime.setHeapValue(r_button_count, button_count, 'i32');
GodotRuntime.setHeapValue(r_axes_count, axes_count, 'i32');

// Hand tracking data.
let has_hand_data = false;
if (input_source.hand && r_hand_joints != 0 && r_hand_radii != 0) {
const hand_joint_array = new Float32Array(25 * 16);
const hand_radii_array = new Float32Array(25);
if (frame.fillPoses(input_source.hand.values(), space, hand_joint_array) && frame.fillJointRadii(input_source.hand.values(), hand_radii_array)) {
GodotRuntime.heapCopy(HEAPF32, hand_joint_array, r_hand_joints);
GodotRuntime.heapCopy(HEAPF32, hand_radii_array, r_hand_radii);
has_hand_data = true;
}
}
GodotRuntime.setHeapValue(r_has_hand_data, has_hand_data ? 1 : 0, 'i32');

return true;
},

Expand Down
56 changes: 55 additions & 1 deletion modules/webxr/native/webxr.externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,27 @@ XRFrame.prototype.session;
XRFrame.prototype.getViewerPose = function (referenceSpace) {};

/**
*
* @param {XRSpace} space
* @param {XRSpace} baseSpace
* @return {XRPose}
*/
XRFrame.prototype.getPose = function (space, baseSpace) {};

/**
* @param {Array<XRSpace>} spaces
* @param {XRSpace} baseSpace
* @param {Float32Array} transforms
* @return {boolean}
*/
XRFrame.prototype.fillPoses = function (spaces, baseSpace, transforms) {};

/**
* @param {Array<XRJointSpace>} jointSpaces
* @param {Float32Array} radii
* @return {boolean}
*/
XRFrame.prototype.fillJointRadii = function (jointSpaces, radii) {};

/**
* @constructor
*/
Expand Down Expand Up @@ -498,11 +512,51 @@ XRInputSource.prototype.targetRayMode;
*/
XRInputSource.prototype.targetRaySpace;

/**
* @type {?XRHand}
*/
XRInputSource.prototype.hand;

/**
* @constructor
*/
function XRHand() {};

/**
* Note: In fact, XRHand acts like a Map<string, XRJointSpace>, but I don't know
* how to represent that here. So, we're just giving the one method we call.
*
* @return {Array<XRJointSpace>}
*/
XRHand.prototype.values = function () {};

/**
* @type {number}
*/
XRHand.prototype.size;

/**
* @param {string} key
* @return {XRJointSpace}
*/
XRHand.prototype.get = function (key) {};

/**
* @constructor
*/
function XRSpace() {};

/**
* @constructor
* @extends {XRSpace}
*/
function XRJointSpace() {};

/**
* @type {string}
*/
XRJointSpace.prototype.jointName;

/**
* @constructor
*/
Expand Down
2 changes: 2 additions & 0 deletions modules/webxr/webxr_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ void WebXRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_optional_features", "optional_features"), &WebXRInterface::set_optional_features);
ClassDB::bind_method(D_METHOD("get_optional_features"), &WebXRInterface::get_optional_features);
ClassDB::bind_method(D_METHOD("get_reference_space_type"), &WebXRInterface::get_reference_space_type);
ClassDB::bind_method(D_METHOD("get_enabled_features"), &WebXRInterface::get_enabled_features);
ClassDB::bind_method(D_METHOD("set_requested_reference_space_types", "requested_reference_space_types"), &WebXRInterface::set_requested_reference_space_types);
ClassDB::bind_method(D_METHOD("get_requested_reference_space_types"), &WebXRInterface::get_requested_reference_space_types);
ClassDB::bind_method(D_METHOD("is_input_source_active", "input_source_id"), &WebXRInterface::is_input_source_active);
Expand All @@ -56,6 +57,7 @@ void WebXRInterface::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "optional_features", PROPERTY_HINT_NONE), "set_optional_features", "get_optional_features");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "requested_reference_space_types", PROPERTY_HINT_NONE), "set_requested_reference_space_types", "get_requested_reference_space_types");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "reference_space_type", PROPERTY_HINT_NONE), "", "get_reference_space_type");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "enabled_features", PROPERTY_HINT_NONE), "", "get_enabled_features");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "visibility_state", PROPERTY_HINT_NONE), "", "get_visibility_state");

ADD_SIGNAL(MethodInfo("session_supported", PropertyInfo(Variant::STRING, "session_mode"), PropertyInfo(Variant::BOOL, "supported")));
Expand Down
1 change: 1 addition & 0 deletions modules/webxr/webxr_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class WebXRInterface : public XRInterface {
virtual void set_requested_reference_space_types(String p_requested_reference_space_types) = 0;
virtual String get_requested_reference_space_types() const = 0;
virtual String get_reference_space_type() const = 0;
virtual String get_enabled_features() const = 0;
virtual bool is_input_source_active(int p_input_source_id) const = 0;
virtual Ref<XRPositionalTracker> get_input_source_tracker(int p_input_source_id) const = 0;
virtual TargetRayMode get_input_source_target_ray_mode(int p_input_source_id) const = 0;
Expand Down
Loading
Loading