XRHandModifier3D
Apply hand joints to named skeleton bones.
XRHandModifier3D runs under Skeleton3D. It matches Left/Right-prefixed Humanoid bones according to tracker hand, such as LeftHand and LeftIndexProximal. Names and hierarchy must match before assessing deformation of a real model.
Full changes positions and rotations; RotationOnly changes rotations. Transforms are relative to parent joints and positions receive skeleton MotionScale. After a valid update, HasTrackingData=false reapplies cached pose. An invalid Palm with HasTrackingData=true instead skips modification; these are different cases.
Modifier output is temporary: read poses inside ModificationProcessed before Skeleton3D restores its base pose. This example stores a copy; LastModified can become stale when the modifier is disabled or the source disappears:
using Reckfell;
public partial class HandPoseProbe : Entity
{
[Export] public Skeleton3D Skeleton { get; set; } = null!;
[Export] public XRHandModifier3D Modifier { get; set; } = null!;
[Export] public int Bone { get; set; }
public Transform3D LastModified { get; private set; } = Transform3D.Identity;
public override void _Ready()
{
if (Skeleton is null || Modifier is null || Modifier.GetSkeleton() != Skeleton
|| Bone < 0 || Bone >= Skeleton.GetBoneCount())
{
ReckfellApi.PushError("HandPoseProbe: assign a matching skeleton, modifier and bone index.");
return;
}
Modifier.ModificationProcessed += Capture;
}
private void Capture() => LastModified = Skeleton.GetBonePose(Bone);
public override void _ExitTree()
{
if (Modifier is not null && ReckfellObject.IsInstanceValid(Modifier))
Modifier.ModificationProcessed -= Capture;
}
}Important source limitation: the ORIENTATION_VALID scan does not become a per-child validity guard before application. Partially invalid child data was not accepted by this test; used joints and parents need a consistent valid set. Active=false disables processing. Do not hide invalidity by manually substituting flags on a real provider.
Fourteen checks used a real Skeleton3D, all 26 matched bones and synthetic joints. Modes, cache, MotionScale, tracker changes and the exact HandPoseProbe were exercised. Real hands, skin weights, deformation, animation blending and image quality were not checked. Setup and pinch: hand tracking.
Declarations checked against C# SDK 1.0.0. Expand a name to see declarations and documentation.
Constructors1
XRHandModifier3DConstructor
public XRHandModifier3D();Creates a modifier with the left HandTracker and BoneUpdate=Full. Parent under Skeleton3D with matching bone names and an XRHandTracker provider. Creates no model, skin weights, collision or XR session.
Properties2
BoneUpdateProperty
public XRHandModifier3D.BoneUpdateEnum BoneUpdate { get; set; }Update mode, initially Full. Full applies relative positions and rotations; RotationOnly leaves base bone positions and applies rotations. Input positions are multiplied by skeleton MotionScale, not automatically by WorldScale. Whole-hand data loss can reapply the previous relative pose.
HandTrackerProperty
public StringName HandTracker { get; set; }XRHandTracker name, initially /user/hand_tracker/left. Inside the tree the setter rebuilds bone mapping and clears cached relative transforms even when repeating the name. Do not assign every frame. Creates no tracker and enables no hardware tracking.
Methods4
GetBoneUpdateXRHandModifier3D.BoneUpdateEnum
public XRHandModifier3D.BoneUpdateEnum GetBoneUpdate();Configured Full/RotationOnly mode. Neither tracking status nor proof of successful skeleton processing.
XRHandModifier3D.BoneUpdateEnumStored bone mode.
GetHandTrackerStringName
public StringName GetHandTracker();Configured tracker name; does not establish presence or fresh data.
StringNameStored tracker name.
SetBoneUpdatevoid
public void SetBoneUpdate(XRHandModifier3D.BoneUpdateEnum boneUpdate);Update mode, initially Full. Full applies relative positions and rotations; RotationOnly leaves base bone positions and applies rotations. Input positions are multiplied by skeleton MotionScale, not automatically by WorldScale. Whole-hand data loss can reapply the previous relative pose.
| Name | Type | Default |
|---|---|---|
boneUpdate | XRHandModifier3D.BoneUpdateEnum | — |
boneUpdateFull or RotationOnly; Max is the bound, not a mode. The native setter checks bounds.
SetHandTrackervoid
public void SetHandTracker(StringName trackerName);XRHandTracker name, initially /user/hand_tracker/left. Inside the tree the setter rebuilds bone mapping and clears cached relative transforms even when repeating the name. Do not assign every frame. Creates no tracker and enables no hardware tracking.
| Name | Type | Default |
|---|---|---|
trackerName | StringName | — |
trackerNameName of a left/right or custom registered XRHandTracker; repeating the in-tree setter also resets the cache.
XRHandModifier3D.BoneUpdateEnum
| Value | Description |
|---|---|
Full = 0 | The skeleton's bones are fully updated (both position and rotation) to match the tracked bones. |
Max = 2 | Represents the size of the |
RotationOnly = 1 | The skeleton's bones are only rotated to align with the tracked bones, preserving bone length. |