Get Velocity for tracked hands?

Is there a way to get the velocity of tracked hands? I’m adding hand support to a project that already uses controllers and I already had a Velocity action in my XRI Default Input Actions that I’ve been using to check the velocity of the controllers:

Since the derived bindings include a Hand Interaction binding, I thought that it might return velocity for my tracked hands when I’m in hand tracking mode, but it doesn’t appear to. Is there anything I might be overlooking or is there no built-in way to get the velocity of a tracked hand?

Not with the Input System (though you can make your own custom device and pump that data through if you need the Input System editor interface), you’ll need to call the XR Hands APIs for that. Once you have the XRHandJoint from the XRHand you care about, just call TryGetLinearVelocity/TryGetAngularVelocity on it, depending on which one you care about.

great this looks like what i was looking for thank you.

@unity_andrewc hmm… so i tried setting this up and when i call TryGetLinearVelocity on my XRHandJoint, its returning false, failing to get the velocity.

Here is how I’m getting the XRHandJoints:

var handSubsystems = new List<XRHandSubsystem>();
SubsystemManager.GetSubsystems(handSubsystems);
_leftXRHand = handSubsystems[0].leftHand;
_rightXRHand = handSubsystems[0].rightHand;
_leftVelocityJoint = _leftXRHand.GetJoint(XRHandJointID.Palm);
_rightVelocityJoint = _rightXRHand.GetJoint(XRHandJointID.Palm);

and then when trying to get one of the velocities:

Vector3 linearVelocity;
if (_instance._leftVelocityJoint.TryGetLinearVelocity(out linearVelocity)) {
    return linearVelocity;
}
else {
    Debug.Log("failed to get linear velocity from the joint");
    return linearVelocity;
}

Everything look right? I tried with XRHandJointID.Wrist and it was the same result…

Not all platforms or even all OpenXR runtimes support joint velocity, it might be that you’re on one that doesn’t support it. Also, I doubt it has anything to do with your particular issue, but returning the linearVelocity value either way from your function there seems problematic to me - it’ll either be stale or zeroed out, depending on implementation.

This is with a Quest 3… I guess it doesn’t support it?

My fallback solution was to use the Aim Pose transform (assigned to _leftHandPositionTransform, etc) from the XR Rig to track the position and calculate velocity like this:

_leftHandVelocity = (_leftHandPositionTransform.position - _lastLeftHandPos) / Time.deltaTime;
_rightHandVelocity = (_rightHandPositionTransform.position - _lastRightHandPos) / Time.deltaTime;
_lastLeftHandPos = _leftHandPositionTransform.position;
_lastRightHandPos = _rightHandPositionTransform.position;

It definitely seems to produce velocities of larger magnitudes than what I was getting with the InputActionReference with the controllers.

Does this seem sufficient or is there another way you’d recommend?

That seems odd, I thought Quest 3 would support that, but I’m not sure. As for the manual velocity tracking - depending on surrounding code, you might be responding to that twice a frame, which would probably need you mean to skip one of the update types.