48 private Vector3[] _backingJointPositions;
51 if (_backingJointPositions ==
null ||
56 return _backingJointPositions;
94 for (
int i = 0; i < 5; i++) {
95 Vector3 baseMetacarpal =
ToLocal(
98 for (
int j = 0; j < 4; j++) {
111 Vector3 prevJoint = Vector3.zero;
112 Vector3 nextJoint = Vector3.zero;
113 Quaternion boneRot = Quaternion.identity;
116 for (
int fingerIdx = 0; fingerIdx < 5; fingerIdx++) {
117 for (
int jointIdx = 0; jointIdx < 4; jointIdx++) {
118 boneIdx = fingerIdx * 4 + jointIdx;
122 if ((nextJoint - prevJoint).normalized == Vector3.zero) {
124 boneRot = Quaternion.identity;
127 boneRot = Quaternion.LookRotation(
128 (nextJoint - prevJoint).normalized,
129 Vector3.Cross((nextJoint - prevJoint).normalized,
131 (
isLeft ? -Vector3.up : Vector3.up)
140 intoHand.GetBone(boneIdx).Fill(
141 prevJoint: prevJoint.ToVector(),
142 nextJoint: nextJoint.ToVector(),
143 center: ((nextJoint + prevJoint) / 2f).ToVector(),
144 direction: (
palmRot * Vector3.forward).ToVector(),
145 length: (prevJoint - nextJoint).magnitude,
148 rotation: boneRot.ToLeapQuaternion());
150 intoHand.
Fingers[fingerIdx].Fill(
155 tipPosition: nextJoint.ToVector(),
156 direction: (boneRot * Vector3.forward).ToVector(),
188 palmPosition:
palmPos.ToVector(),
189 stabilizedPalmPosition:
palmPos.ToVector(),
190 palmVelocity: Vector3.zero.ToVector(),
191 palmNormal: (
palmRot * Vector3.down).ToVector(),
192 rotation: (
palmRot.ToLeapQuaternion()),
193 direction: (
palmRot * Vector3.forward).ToVector(),
194 wristPosition: wristPos.ToVector()
212 #region Byte Encoding & Decoding
239 throw new System.IndexOutOfRangeException(
240 "Not enough room to read bytes for VectorHand encoding starting at offset "
241 + offset +
" for array of size " + bytes +
"; need at least "
246 isLeft = bytes[offset++] == 0x00;
249 for (
int i = 0; i < 3; i++) {
251 BitConverterNonAlloc.ToInt16(bytes, ref offset))
254 palmRot = Utils.DecompressBytesToQuat(bytes, ref offset);
258 for (
int j = 0; j < 3; j++) {
259 jointPositions[i][j] = VectorHandExtensions.ByteToFloat(bytes[offset++]);
271 public void FillBytes(
byte[] bytesToFill, ref
int offset) {
272 if (_backingJointPositions ==
null) {
273 throw new System.InvalidOperationException(
274 "Joint positions array is null. You must fill a VectorHand with data before "
275 +
"you can use it to fill byte representations.");
279 throw new System.IndexOutOfRangeException(
280 "Not enough room to fill bytes for VectorHand encoding starting at offset "
281 + offset +
" for array of size " + bytesToFill.Length +
"; need at least "
286 bytesToFill[offset++] =
isLeft ? (byte)0x00 : (
byte)0x01;
289 for (
int i = 0; i < 3; i++) {
290 BitConverterNonAlloc.GetBytes(Convert.ToInt16(
palmPos[i] * 4096f),
296 Utils.CompressQuatToBytes(
palmRot, bytesToFill, ref offset);
300 for (
int i = 0; i < 3; i++) {
301 bytesToFill[offset++] =
314 int unusedOffset = 0;
315 FillBytes(bytesToFill, ref unusedOffset);
334 if (fromHand ==
null) {
335 for (
int i = offset; i < offset +
NUM_BYTES; i++) {
346 private static VectorHand s_backingCachedVectorHand;
347 private static VectorHand s_cachedVectorHand {
349 if (s_backingCachedVectorHand ==
null) {
352 return s_backingCachedVectorHand;
356 private static Vector3[] s_backingJointsBuffer =
358 private static Vector3[] s_jointsBuffer {
360 if (s_backingJointsBuffer ==
null) {
363 return s_backingJointsBuffer;
392 s_cachedVectorHand._backingJointPositions = s_jointsBuffer;
393 s_cachedVectorHand.
FillBytes(bytes, ref offset, fromHand);
404 public static Vector3
ToWorld(Vector3 localPoint,
405 Vector3 localOrigin, Quaternion localRot) {
406 return (localRot * localPoint) + localOrigin;
413 public static Vector3
ToLocal(Vector3 worldPoint,
414 Vector3 localOrigin, Quaternion localRot) {
415 return Quaternion.Inverse(localRot) * (worldPoint - localOrigin);
426 if (a ==
null || b ==
null)
return false;
428 throw new System.Exception(
"VectorHands must be interpolated with the " +
449 if (a ==
null || b ==
null || c ==
null || d ==
null) {
453 throw new System.Exception(
"VectorHands must be interpolated with the " +
478 #region Utility Extension Methods
480 public static class VectorHandExtensions {
482 #region VectorHand Instance API
495 public static Bone GetBone(
this Hand hand,
int boneIdx) {
496 return hand.
Fingers[boneIdx / 4].bones[boneIdx % 4];
502 public static byte FloatToByte(
float inFloat,
float movementRange = 0.3f) {
503 float clamped = Mathf.Clamp(inFloat, -movementRange / 2f, movementRange / 2f);
504 clamped += movementRange / 2f;
505 clamped /= movementRange;
507 clamped = Mathf.Floor(clamped);
508 return (
byte)clamped;
514 public static float ByteToFloat(
byte inByte,
float movementRange = 0.3f) {
515 float clamped = (float)inByte;
517 clamped *= movementRange;
518 clamped -= movementRange / 2f;
The Bone class represents a tracked bone.
BoneType
Enumerates the type of bones.
The Finger class represents a tracked finger.
FingerType
Enumerates the names of the fingers.
The Hand class reports the physical characteristics of a detected hand.
bool IsLeft
Identifies whether this Hand is a left hand.
Arm Arm
The arm to which this hand is attached.
Vector PalmPosition
The center position of the palm.
List< Finger > Fingers
The list of Finger objects detected in this frame that are attached to this hand, given in order from...
LeapQuaternion Rotation
The rotation of the hand as a quaternion.
A Vector-based encoding of a Leap Hand.
void FillBytes(byte[] bytesToFill, ref int offset)
Fills the provided byte array with a compressed, 86-byte form of this VectorHand, starting at the pro...
void ReadBytes(byte[] bytes, ref int offset)
Fills this VectorHand with data read from the provided byte array, starting at the provided offset.
void FillBytes(byte[] bytes, ref int offset, Hand fromHand)
Shortcut for encoding a Leap hand into a VectorHand representation and compressing it immediately int...
int numBytesRequired
The number of bytes required to encode a VectorHand into its byte representation. The byte representa...
static void StaticFillBytes(byte[] bytes, Hand fromHand)
Fills bytes using a thread-safe (ThreadStatic) cached VectorHand to encode the provided Hand....
static Vector3 ToLocal(Vector3 worldPoint, Vector3 localOrigin, Quaternion localRot)
Converts a world-space point to a local-space point given the local space's origin and rotation.
static void StaticFillBytes(byte[] bytes, ref int offset, Hand fromHand)
Fills bytes at the argument offset using a thread-safe (ThreadStatic) cached VectorHand to encode the...
void ReadBytes(byte[] bytes, ref int offset, Hand intoHand)
Shortcut for reading a VectorHand-encoded byte representation of a Leap hand and decoding it immediat...
static Vector3 tweakWristPosition
void Encode(Hand fromHand)
VectorHand CopyFrom(VectorHand h)
Copies a VectorHand from another VectorHand
void ReadBytes(byte[] bytes, int offset=0)
Fills this VectorHand with data read from the provided byte array, starting at the provided offset.
static void StaticFillBytes(byte[] bytes, int offset, Hand fromHand)
Fills bytes at the argument offset using a thread-safe (ThreadStatic) cached VectorHand to encode the...
VectorHand(Hand hand)
Constructs a VectorHand representation from a Leap hand. This allocates a vector array for the encode...
bool FillLerped(VectorHand a, VectorHand b, float t)
Fills the ref-argument VectorHand with interpolated data between the two other VectorHands,...
void Decode(Hand intoHand)
static Vector3 ToWorld(Vector3 localPoint, Vector3 localOrigin, Quaternion localRot)
Converts a local-space point to a world-space point given the local space's origin and rotation.
bool FillSplined(VectorHand a, VectorHand b, VectorHand c, VectorHand d, float t)
Fills the ref-argument VectorHand with interpolated data between the 4 other VectorHands,...
void FillBytes(byte[] bytesToFill)
Fills the provided byte array with a compressed, 86-byte form of this VectorHand.
const int NUM_JOINT_POSITIONS
An interface that signifies this class can interpolate via the standard techniques
bool FillSplined(T a, T b, T c, T d, float t)
bool FillLerped(T from, T to, float t)
A position and rotation. You can multiply two poses; this acts like Matrix4x4 multiplication,...
The Vector struct represents a three-component mathematical vector or point such as a direction or po...
static readonly Vector Zero
The zero vector: (0, 0, 0)