@ -178,9 +178,22 @@ func _process(_delta: float) -> void:
data [ " left_wrist " ] = _xform_to_mat16 ( left_wrist_rel )
data [ " left_wrist " ] = _xform_to_mat16 ( left_wrist_rel )
data [ " right_wrist " ] = _xform_to_mat16 ( right_wrist_rel )
data [ " right_wrist " ] = _xform_to_mat16 ( right_wrist_rel )
# Get XRHandTracker references (used for finger positions AND wrist rotation)
var left_ht = XRServer . get_tracker ( & " /user/hand_tracker/left " ) as XRHandTracker
var right_ht = XRServer . get_tracker ( & " /user/hand_tracker/right " ) as XRHandTracker
# Hand joint positions (25 joints per hand, relative to wrist)
# Hand joint positions (25 joints per hand, relative to wrist)
var left_hand_pos : = _get_hand_positions ( tracker , JOINT_LEFT_HAND_START , left_wrist_xform )
var right_hand_pos : = _get_hand_positions ( tracker , JOINT_RIGHT_HAND_START , right_wrist_xform )
# Use XRHandTracker for finger articulation — XRBodyTracker doesn't provide it on Quest 3
var left_hand_pos : Array
var right_hand_pos : Array
if left_ht and left_ht . has_tracking_data :
left_hand_pos = _get_hand_positions_ht ( left_ht )
else :
left_hand_pos = _get_hand_positions ( tracker , JOINT_LEFT_HAND_START , left_wrist_xform )
if right_ht and right_ht . has_tracking_data :
right_hand_pos = _get_hand_positions_ht ( right_ht )
else :
right_hand_pos = _get_hand_positions ( tracker , JOINT_RIGHT_HAND_START , right_wrist_xform )
data [ " left_hand_pos " ] = left_hand_pos
data [ " left_hand_pos " ] = left_hand_pos
data [ " right_hand_pos " ] = right_hand_pos
data [ " right_hand_pos " ] = right_hand_pos
@ -203,12 +216,10 @@ func _process(_delta: float) -> void:
# hand tracking has much better wrist rotation detection
# hand tracking has much better wrist rotation detection
var left_wrist_body : = left_wrist_xform
var left_wrist_body : = left_wrist_xform
var right_wrist_body : = right_wrist_xform
var right_wrist_body : = right_wrist_xform
var left_ht = XRServer . get_tracker ( & " /user/hand_tracker/left " ) as XRHandTracker
if left_ht and left_ht . has_tracking_data :
if left_ht and left_ht . has_tracking_data :
var ht_wrist : = left_ht . get_hand_joint_transform ( XRHandTracker . HAND_JOINT_WRIST )
var ht_wrist : = left_ht . get_hand_joint_transform ( XRHandTracker . HAND_JOINT_WRIST )
if ht_wrist . origin != Vector3 . ZERO :
if ht_wrist . origin != Vector3 . ZERO :
left_wrist_body = ht_wrist
left_wrist_body = ht_wrist
var right_ht = XRServer . get_tracker ( & " /user/hand_tracker/right " ) as XRHandTracker
if right_ht and right_ht . has_tracking_data :
if right_ht and right_ht . has_tracking_data :
var ht_wrist : = right_ht . get_hand_joint_transform ( XRHandTracker . HAND_JOINT_WRIST )
var ht_wrist : = right_ht . get_hand_joint_transform ( XRHandTracker . HAND_JOINT_WRIST )
if ht_wrist . origin != Vector3 . ZERO :
if ht_wrist . origin != Vector3 . ZERO :
@ -264,7 +275,29 @@ func _xform_to_mat16(xform: Transform3D) -> Array:
]
]
## Get 25 hand joint positions relative to wrist, as flat array (75 floats)
## Get 25 hand joint positions from XRHandTracker, relative to wrist (75 floats).
## Joint order: PALM(0), THUMB_META..TIP(2-5), INDEX(6-10), MIDDLE(11-15),
## RING(16-20), LITTLE(21-25) — skipping WRIST(1).
## This matches the format expected by dex-retargeting / xr_teleoperate.
func _get_hand_positions_ht ( hand_tracker : XRHandTracker ) - > Array :
var wrist_xform : = hand_tracker . get_hand_joint_transform ( XRHandTracker . HAND_JOINT_WRIST )
var wrist_inv : = wrist_xform . affine_inverse ( )
var positions : = [ ]
positions . resize ( HAND_JOINT_COUNT * 3 ) # 25 * 3 = 75
var out_idx : = 0
for xr_joint in range ( 26 ) : # OpenXR joints 0-25
if xr_joint == 1 : # Skip WRIST
continue
var joint_xform : = hand_tracker . get_hand_joint_transform ( xr_joint )
var rel : = wrist_inv * joint_xform
positions [ out_idx * 3 + 0 ] = rel . origin . x
positions [ out_idx * 3 + 1 ] = rel . origin . y
positions [ out_idx * 3 + 2 ] = rel . origin . z
out_idx += 1
return positions
## Get 25 hand joint positions from XRBodyTracker (fallback), relative to wrist.
## Each joint: [x, y, z] relative to wrist
## Each joint: [x, y, z] relative to wrist
func _get_hand_positions ( tracker : XRBodyTracker , start_idx : int , wrist_xform : Transform3D ) - > Array :
func _get_hand_positions ( tracker : XRBodyTracker , start_idx : int , wrist_xform : Transform3D ) - > Array :
var wrist_inv : = wrist_xform . affine_inverse ( )
var wrist_inv : = wrist_xform . affine_inverse ( )