XRHandTracker
Hand-joint data and separate validity flags.
XRHandTracker stores 26 hand joints. Check tracker availability, whole-hand HasTrackingData and each required joint’s flags separately. VALID differs from TRACKED; a valid estimate is not necessarily directly tracked. A new hand has Type=Hand and Hand=Left but connects no device.
Confirmed constructor defect: initial joint flags are uninitialized. A custom provider must populate them before enabling HasTrackingData. Gameplay reads real-provider data and must not alter flags to bypass checks. Data loss does not clear retained transforms or velocities.
In OpenXR joint transforms are tracking-space values with Humanoid orientation adjustment, not relative to the preceding bone. Radius is meters with PositionValid. Getters do not validate usability for you. HandTrackingSource=Unknown does not establish an optical source; selecting a source creates no gestures or actions.
Synthetic data and the pinch example were checked, not real tracking or model animation. Complete example, setup and diagnosis: hand tracking.
Declarations checked against C# SDK 1.0.0. Expand a name to see declarations and documentation.
Constructors1
XRHandTrackerConstructor
public XRHandTracker();Creates a hand container: Type=Hand, Hand=Left, HasTrackingData=false, source Unknown. Defect: the joint-flag array is uninitialized. A new hand is not valid provider data: a custom provider must fill flags and values before enabling data. Does not automatically register a device.
Properties2
HandTrackingSourceProperty
public XRHandTracker.HandTrackingSourceEnum HandTrackingSource { get; set; }Data source, initially Unknown. Unobstructed and Controller describe the reported kind, NotTracked denotes no tracking; availability depends on the provider. Unknown does not establish optical tracking. The setter changes neither HasTrackingData nor joint flags.
HasTrackingDataProperty
public bool HasTrackingData { get; set; }Whole-hand data flag, initially false. The setter changes only it: populates no joint flags/transforms and creates no default pose. Joint values remain when false but must not drive interactions. The provider owns real-hand state, not gameplay code.
Methods14
GetHandJointAngularVelocityVector3
public Vector3 GetHandJointAngularVelocity(XRHandTracker.HandJoint joint);Returns stored angular velocity. Use requires AngularVelocityValid; the getter applies neither reference frame nor WorldScale.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
Vector3Stored angular velocity; check its flag.
GetHandJointFlagsXRHandTracker.HandJointFlags
public XRHandTracker.HandJointFlags GetHandJointFlags(XRHandTracker.HandJoint joint);Reads joint validity/tracking bits. Before provider initialization values can be arbitrary because of the constructor defect. VALID is not TRACKED. Check HasTrackingData and required bits; velocities have separate bits.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
XRHandTracker.HandJointFlagsJoint mask; values are not guaranteed before initialization.
GetHandJointLinearVelocityVector3
public Vector3 GetHandJointLinearVelocity(XRHandTracker.HandJoint joint);Returns stored linear velocity without checking LinearVelocityValid or converting to gameplay world space. Do not use a retained value after tracking loss.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
Vector3Stored linear velocity; check its flag.
GetHandJointRadiusfloat
public float GetHandJointRadius(XRHandTracker.HandJoint joint);Reads stored radius, initially 0. In OpenXR units are meters and radius is meaningful only with PositionValid. The getter checks no flag and applies no WorldScale.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
floatStored radius float; not a PositionValid check.
GetHandJointTransformTransform3D
public Transform3D GetHandJointTransform(XRHandTracker.HandJoint joint);Returns a Transform3D value without flag checks. In OpenXR it is tracking space with Humanoid orientation adjustment, not a bone-local or world transform. Check PositionValid for position and OrientationValid for rotation. Retained data may be stale.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
Transform3DJoint-transform copy, not a model-bone local pose.
GetHandTrackingSourceXRHandTracker.HandTrackingSourceEnum
public XRHandTracker.HandTrackingSourceEnum GetHandTrackingSource();Returns the stored source. Do not infer it from the runtime name; keep Unknown unknown.
XRHandTracker.HandTrackingSourceEnumStored source, initially Unknown.
GetHasTrackingDatabool
public bool GetHasTrackingData();Reads the whole-hand flag. Specific joint flags are also required; true alone does not validate all 26 joints.
boolWhole-hand flag; does not validate every joint.
SetHandJointAngularVelocityvoid
public void SetHandJointAngularVelocity(XRHandTracker.HandJoint joint, Vector3 angularVelocity);Stores angular velocity without deriving it from rotation or changing AngularVelocityValid. The provider defines space conventions.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
angularVelocity | Vector3 | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
angularVelocityAngular velocity in provider conventions; set validity separately.
SetHandJointFlagsvoid
public void SetHandJointFlags(XRHandTracker.HandJoint joint, XRHandTracker.HandJointFlags flags);Stores one joint mask; changes no transform, velocities or HasTrackingData. A custom provider must explicitly initialize all required joints before publishing data. Do not use this to alter real-hand state from gameplay.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
flags | XRHandTracker.HandJointFlags | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
flagsHandJointFlags mask for one joint; supply accurate data-validity bits.
SetHandJointLinearVelocityvoid
public void SetHandJointLinearVelocity(XRHandTracker.HandJoint joint, Vector3 linearVelocity);Stores linear velocity separately from transform and flags. Derives nothing from the previous frame and does not enable LinearVelocityValid.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
linearVelocity | Vector3 | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
linearVelocityLinear velocity in provider conventions; set validity separately.
SetHandJointRadiusvoid
public void SetHandJointRadius(XRHandTracker.HandJoint joint, float radius);Stores the radius float without range validation or flag changes. The provider must supply a finite physically meaningful value; readback does not establish usability.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
radius | float | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
radiusFinite physical radius; meters in OpenXR. The setter does not validate range.
SetHandJointTransformvoid
public void SetHandJointTransform(XRHandTracker.HandJoint joint, Transform3D transform);Stores a joint transform without recomputing flags or velocities. Provider API, not a model-bone movement command.
| Name | Type | Default |
|---|---|---|
joint | XRHandTracker.HandJoint | — |
transform | Transform3D | — |
jointOne of 26 HandJoint values, Palm…PinkyFingerTip. Max is the bound, not a valid joint.
transformProvider-space transform; do not pre-apply gameplay origin.
SetHandTrackingSourcevoid
public void SetHandTrackingSource(XRHandTracker.HandTrackingSourceEnum source);Data source, initially Unknown. Unobstructed and Controller describe the reported kind, NotTracked denotes no tracking; availability depends on the provider. Unknown does not establish optical tracking. The setter changes neither HasTrackingData nor joint flags.
| Name | Type | Default |
|---|---|---|
source | XRHandTracker.HandTrackingSourceEnum | — |
sourceReported source; not a device/tracking enable command.
SetHasTrackingDatavoid
public void SetHasTrackingData(bool hasData);Whole-hand data flag, initially false. The setter changes only it: populates no joint flags/transforms and creates no default pose. Joint values remain when false but must not drive interactions. The provider owns real-hand state, not gameplay code.
| Name | Type | Default |
|---|---|---|
hasData | bool | — |
hasDataWhole-hand data flag. Does not enable individual-joint validity.
XRHandTracker.HandJoint
| Value | Description |
|---|---|
IndexFingerMetacarpal = 6 | Index finger metacarpal joint. |
IndexFingerPhalanxDistal = 9 | Index finger phalanx distal joint. |
IndexFingerPhalanxIntermediate = 8 | Index finger phalanx intermediate joint. |
IndexFingerPhalanxProximal = 7 | Index finger phalanx proximal joint. |
IndexFingerTip = 10 | Index finger tip joint. |
Max = 26 | Represents the size of the |
MiddleFingerMetacarpal = 11 | Middle finger metacarpal joint. |
MiddleFingerPhalanxDistal = 14 | Middle finger phalanx distal joint. |
MiddleFingerPhalanxIntermediate = 13 | Middle finger phalanx intermediate joint. |
MiddleFingerPhalanxProximal = 12 | Middle finger phalanx proximal joint. |
MiddleFingerTip = 15 | Middle finger tip joint. |
Palm = 0 | Palm joint. |
PinkyFingerMetacarpal = 21 | Pinky finger metacarpal joint. |
PinkyFingerPhalanxDistal = 24 | Pinky finger phalanx distal joint. |
PinkyFingerPhalanxIntermediate = 23 | Pinky finger phalanx intermediate joint. |
PinkyFingerPhalanxProximal = 22 | Pinky finger phalanx proximal joint. |
PinkyFingerTip = 25 | Pinky finger tip joint. |
RingFingerMetacarpal = 16 | Ring finger metacarpal joint. |
RingFingerPhalanxDistal = 19 | Ring finger phalanx distal joint. |
RingFingerPhalanxIntermediate = 18 | Ring finger phalanx intermediate joint. |
RingFingerPhalanxProximal = 17 | Ring finger phalanx proximal joint. |
RingFingerTip = 20 | Ring finger tip joint. |
ThumbMetacarpal = 2 | Thumb metacarpal joint. |
ThumbPhalanxDistal = 4 | Thumb phalanx distal joint. |
ThumbPhalanxProximal = 3 | Thumb phalanx proximal joint. |
ThumbTip = 5 | Thumb tip joint. |
Wrist = 1 | Wrist joint. |
XRHandTracker.HandJointFlags
| Value | Description |
|---|---|
AngularVelocityValid = 32 | The hand joint's angular velocity data is valid. |
LinearVelocityValid = 16 | The hand joint's linear velocity data is valid. |
OrientationTracked = 2 | The hand joint's orientation is actively tracked. May not be set if tracking has been temporarily lost. |
OrientationValid = 1 | The hand joint's orientation data is valid. |
PositionTracked = 8 | The hand joint's position is actively tracked. May not be set if tracking has been temporarily lost. |
PositionValid = 4 | The hand joint's position data is valid. |
XRHandTracker.HandTrackingSourceEnum
| Value | Description |
|---|---|
Controller = 2 | The source of hand tracking data is a controller, meaning that joint positions are inferred from controller inputs. |
Max = 4 | Represents the size of the |
NotTracked = 3 | 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. |
Unknown = 0 | The source of hand tracking data is unknown. |
Unobstructed = 1 | The source of hand tracking data is unobstructed, meaning that an accurate method of hand tracking is used. These include optical hand tracking, data gloves, etc. |