/// <summary> /// Adds keyframe data into these VectorHandCurves at the specified time using the /// provided hand data. /// </summary> public void AddKeyframes(float time, Hand hand) { bool isTracked = hand != null; isTrackedCurve.AddBooleanKey(time, isTracked); if (isTracked) { VectorHand vectorHand = Pool <VectorHand> .Spawn(); try { vectorHand.Encode(hand); palmPosCurves.AddKeyframes(time, vectorHand.palmPos); palmRotCurves.AddKeyframes(time, vectorHand.palmRot); for (int i = 0; i < VectorHand.NUM_JOINT_POSITIONS; i++) { jointPositionCurves[i].AddKeyframes(time, vectorHand.jointPositions[i]); } } finally { Pool <VectorHand> .Recycle(vectorHand); } } }
/// <summary> /// Encodes a Leap hand into a VectorHand representation. /// </summary> public static void Encode(Hand hand, ref VectorHand toVectorHand) { toVectorHand.isLeft = hand.IsLeft; toVectorHand.palmPos = hand.PalmPosition.ToVector3(); toVectorHand.palmRot = hand.Rotation.ToQuaternion(); if (toVectorHand.jointPositions == null || toVectorHand.jointPositions.Length != NUM_JOINT_POSITIONS) { toVectorHand.jointPositions = new Vector3[NUM_JOINT_POSITIONS]; } int boneIdx = 0; for (int i = 0; i < 5; i++) { Vector3 baseMetacarpal = ToLocal(hand.Fingers[i].bones[0].PrevJoint.ToVector3(), toVectorHand.palmPos, toVectorHand.palmRot); toVectorHand.jointPositions[boneIdx++] = baseMetacarpal; for (int j = 0; j < 4; j++) { Vector3 joint = ToLocal(hand.Fingers[i].bones[j].NextJoint.ToVector3(), toVectorHand.palmPos, toVectorHand.palmRot); toVectorHand.jointPositions[boneIdx++] = joint; } } }
/// <summary> /// Samples hand curve data into the provided hand object at the specified time. /// /// If the hand is not tracked at the specified time, the function returns false, /// although hand data is still copied (via interpolation). /// </summary> public bool Sample(float time, Hand intoHand, bool isLeft) { bool isTracked = isTrackedCurve.Evaluate(time) > 0.5f; VectorHand vectorHand = Pool <VectorHand> .Spawn(); try { vectorHand.isLeft = isLeft; vectorHand.palmPos = palmPosCurves.Evaluate(time); vectorHand.palmRot = palmRotCurves.Evaluate(time); for (int i = 0; i < VectorHand.NUM_JOINT_POSITIONS; i++) { vectorHand.jointPositions[i] = jointPositionCurves[i].Evaluate(time); } vectorHand.Decode(intoHand); // Fill temporal data if we have a hand from the previous sampling. if (_lastHand != null) { intoHand.FillTemporalData(_lastHand, Time.deltaTime); _lastHand.CopyFrom(intoHand); } else { _lastHand = new Hand(); } } finally { Pool <VectorHand> .Recycle(vectorHand); } return(isTracked); }
/// <summary> /// Decodes a VectorHand representation into a Leap hand. /// </summary> public static void Decode(ref VectorHand vectorHand, Hand toHand) { int boneIdx = 0; Vector3 prevJoint = Vector3.zero; Vector3 nextJoint = Vector3.zero; Quaternion boneRot = Quaternion.identity; var isLeft = vectorHand.isLeft; var palmPos = vectorHand.palmPos; var palmRot = vectorHand.palmRot; var jointPositions = vectorHand.jointPositions; // Fill fingers. for (int fingerIdx = 0; fingerIdx < 5; fingerIdx++) { for (int jointIdx = 0; jointIdx < 4; jointIdx++) { boneIdx = fingerIdx * 4 + jointIdx; prevJoint = jointPositions[fingerIdx * 5 + jointIdx]; nextJoint = jointPositions[fingerIdx * 5 + jointIdx + 1]; if ((nextJoint - prevJoint).normalized == Vector3.zero) { // Thumb "metacarpal" slot is an identity bone. boneRot = Quaternion.identity; } else { boneRot = Quaternion.LookRotation((nextJoint - prevJoint).normalized, Vector3.Cross((nextJoint - prevJoint).normalized, (fingerIdx == 0 ? (isLeft ? -Vector3.up : Vector3.up) : Vector3.right))); } // Convert to world space from palm space. nextJoint = ToWorld(nextJoint, palmPos, palmRot); prevJoint = ToWorld(prevJoint, palmPos, palmRot); boneRot = palmRot * boneRot; toHand.GetBone(boneIdx).Fill(prevJoint: prevJoint.ToVector(), nextJoint: nextJoint.ToVector(), center: ((nextJoint + prevJoint) / 2f).ToVector(), direction: (palmRot * Vector3.forward).ToVector(), length: (prevJoint - nextJoint).magnitude, width: 0.01f, type: (Bone.BoneType)jointIdx, rotation: boneRot.ToLeapQuaternion()); } toHand.Fingers[fingerIdx].Fill(frameId: -1, handId: (isLeft ? 0 : 1), fingerId: fingerIdx, timeVisible: Time.time, tipPosition: nextJoint.ToVector(), tipVelocity: Vector.Zero, direction: (boneRot * Vector3.forward).ToVector(), stabilizedTipPosition: nextJoint.ToVector(), width: 1f, length: 1f, isExtended: true, type: (Finger.FingerType)fingerIdx); } // Fill arm data. toHand.Arm.Fill(ToWorld(new Vector3(0f, 0f, -0.3f), palmPos, palmRot).ToVector(), ToWorld(new Vector3(0f, 0f, -0.055f), palmPos, palmRot).ToVector(), ToWorld(new Vector3(0f, 0f, -0.125f), palmPos, palmRot).ToVector(), Vector.Zero, 0.3f, 0.05f, (palmRot).ToLeapQuaternion()); // Finally, fill hand data. toHand.Fill(frameID: -1, id: (isLeft ? 0 : 1), confidence: 1f, grabStrength: 0.5f, grabAngle: 100f, pinchStrength: 0.5f, pinchDistance: 50f, palmWidth: 0.085f, isLeft: isLeft, timeVisible: 1f, fingers: null /* already uploaded finger data */, palmPosition: palmPos.ToVector(), stabilizedPalmPosition: palmPos.ToVector(), palmVelocity: Vector3.zero.ToVector(), palmNormal: (palmRot * Vector3.down).ToVector(), rotation: (palmRot.ToLeapQuaternion()), direction: (palmRot * Vector3.forward).ToVector(), wristPosition: ToWorld(new Vector3(0f, 0f, -0.055f), palmPos, palmRot).ToVector()); }