diff --git a/doc/classes/XRHandModifier3D.xml b/doc/classes/XRHandModifier3D.xml index 7e08d3f6876f..3192913b876b 100644 --- a/doc/classes/XRHandModifier3D.xml +++ b/doc/classes/XRHandModifier3D.xml @@ -5,6 +5,8 @@ This node uses hand tracking data from a [XRHandTracker] to animate the skeleton of a hand mesh. + This node positions itself at the [constant XRHandTracker.HAND_JOINT_PALM] position and scales itself to [member XRServer.world_scale]. Adding the hand model as a child of this node will result in the model being positioned and scaled correctly for XR experiences. + The hand tracking position-data is scaled by [member Skeleton3D.motion_scale] when applied to the skeleton, which can be used to adjust the tracked hand to match the scale of the hand model. $DOCS_URL/tutorials/xr/index.html diff --git a/scene/3d/xr_hand_modifier_3d.cpp b/scene/3d/xr_hand_modifier_3d.cpp index 3c3851971323..1e1449b54ba5 100644 --- a/scene/3d/xr_hand_modifier_3d.cpp +++ b/scene/3d/xr_hand_modifier_3d.cpp @@ -213,13 +213,15 @@ void XRHandModifier3D::_update_skeleton() { return; } + // Get the world and skeleton scale. + const float ws = xr_server->get_world_scale(); + const float ss = skeleton->get_motion_scale(); + // We cache our transforms so we can quickly calculate local transforms. bool has_valid_data[XRHandTracker::HAND_JOINT_MAX]; Transform3D transforms[XRHandTracker::HAND_JOINT_MAX]; Transform3D inv_transforms[XRHandTracker::HAND_JOINT_MAX]; - const float ws = xr_server->get_world_scale(); - if (tracker->get_has_tracking_data()) { for (int joint = 0; joint < XRHandTracker::HAND_JOINT_MAX; joint++) { BitField flags = tracker->get_hand_joint_flags((XRHandTracker::HandJoint)joint); @@ -227,7 +229,7 @@ void XRHandModifier3D::_update_skeleton() { if (has_valid_data[joint]) { transforms[joint] = tracker->get_hand_joint_transform((XRHandTracker::HandJoint)joint); - transforms[joint].origin *= ws; + transforms[joint].origin *= ss; inv_transforms[joint] = transforms[joint].inverse(); } } @@ -253,8 +255,11 @@ void XRHandModifier3D::_update_skeleton() { skeleton->set_bone_pose_rotation(joints[joint].bone, Quaternion(relative_transform.basis)); } - // Transform to the skeleton pose. - set_transform(transforms[XRHandTracker::HAND_JOINT_PALM]); + // Transform to the skeleton pose. This uses the HAND_JOINT_PALM position without skeleton-scaling, as it + // must be positioned to match the physical hand location. It is scaled with the world space to match + // the scaling done to the camera and eyes. + set_transform( + tracker->get_hand_joint_transform(XRHandTracker::HAND_JOINT_PALM) * ws); set_visible(true); } else {