private float GetAngle(Leap.Hand hand) { Vector3 proximalAxis = hand.DistalAxis() * -1f; Vector3 radialAxis = hand.RadialAxis(); if (hand.IsLeft) { radialAxis *= -1f; } List <float> fingerAngles = new List <float> { Vector3.SignedAngle(proximalAxis, hand.GetIndex().Direction.ToVector3(), radialAxis), Vector3.SignedAngle(proximalAxis, hand.GetMiddle().Direction.ToVector3(), radialAxis), Vector3.SignedAngle(proximalAxis, hand.GetRing().Direction.ToVector3(), radialAxis), Vector3.SignedAngle(proximalAxis, hand.GetPinky().Direction.ToVector3(), radialAxis) }; List <float> fingerAnglesShifted = new List <float>(); foreach (float angle in fingerAngles) { float shiftedAngle = angle; if (angle < -90f) { shiftedAngle += 360f; } fingerAnglesShifted.Add(shiftedAngle); } angle = 0.25f * (fingerAnglesShifted[0] + fingerAnglesShifted[1] + fingerAnglesShifted[2] + fingerAnglesShifted[3]); return(angle); }
//Determines if the fingers are extended and the palm is facing up public bool IsFlatHand(Leap.Hand hand) { float angle = Vector3.Angle(hand.PalmNormal.ToVector3(), Vector3.up); //Debug.Log(angle); return((hand.GrabAngle <= 1f) && (angle < 120f)); }
//Check pinch and grab pose public bool IsPinching(Leap.Hand hand) { if (Hands.GetIndex(hand).IsExtended) { return(false); } //return hand.PinchStrength > .9f; //first and foremost we need the index to be pinched, if it it is we have a true bool pinch = checkPinchOfFinger(hand, "index"); //if we are in pinch with index check to see if other fingers are not. if (pinch) { string[] fings = { "ring", "pinky" }; foreach (string f in fings) { //If any other finger is in pinch return false if (checkPinchOfFinger(hand, f)) { return(false); } } } return(pinch); }
private static SerializableHand ToSerializableHand(Hand leapHand) { var hand = new SerializableHand { id = leapHand.Id, frameID = leapHand.FrameId, confidence = leapHand.Confidence, grabStrength = leapHand.GrabStrength, grabAngle = leapHand.GrabAngle, pinchStrength = leapHand.PinchStrength, pinchDistance = leapHand.PinchDistance, palmWidth = leapHand.PalmWidth, isLeft = leapHand.IsLeft, timeVisible = leapHand.TimeVisible, arm = ToSerializableArm(leapHand.Arm), fingers = leapHand.Fingers.Select(ToSerializableFinger).ToList(), palmPosition = ToSerializableVector(leapHand.PalmPosition), stabilizedPalmPosition = ToSerializableVector(leapHand.StabilizedPalmPosition), palmVelocity = ToSerializableVector(leapHand.PalmVelocity), palmNormal = ToSerializableVector(leapHand.PalmNormal), direction = ToSerializableVector(leapHand.Direction), wristPosition = ToSerializableVector(leapHand.WristPosition) }; return hand; }
private float DuckPinchMetric(Leap.Hand hand) { Vector3 thumbDistal = hand.GetThumb().bones[3].PrevJoint.ToVector3(); Vector3 thumbTip = hand.GetThumb().TipPosition.ToVector3(); Vector3 indexMetacarpal = hand.GetIndex().bones[0].PrevJoint.ToVector3(); Vector3 indexProximal = hand.GetIndex().bones[1].PrevJoint.ToVector3(); Vector3 indexTip = hand.GetIndex().TipPosition.ToVector3(); Vector3 middleMetacarpal = hand.GetMiddle().bones[0].PrevJoint.ToVector3(); Vector3 middleTip = hand.GetMiddle().bones[3].PrevJoint.ToVector3(); Vector3 ringMetacarpal = hand.GetMiddle().bones[0].PrevJoint.ToVector3(); Vector3 ringTip = hand.GetRing().bones[3].PrevJoint.ToVector3(); // Project all except thumb onto a plane Vector3 projectionPlane = Vector3.Cross(hand.GetIndex().bones[2].Direction.ToVector3(), hand.PalmarAxis()).normalized; if (hand.IsRight) { // convert to left-handed-rule for Unity projectionPlane *= -1f; } Vector3 planeOrigin = indexProximal; indexProximal = Vector3.zero; indexMetacarpal = Vector3.ProjectOnPlane(indexMetacarpal - planeOrigin, projectionPlane) + planeOrigin; indexTip = Vector3.ProjectOnPlane(indexTip - planeOrigin, projectionPlane) + planeOrigin; middleMetacarpal = Vector3.ProjectOnPlane(middleMetacarpal - planeOrigin, projectionPlane) + planeOrigin; middleTip = Vector3.ProjectOnPlane(middleTip - planeOrigin, projectionPlane) + planeOrigin; ringMetacarpal = Vector3.ProjectOnPlane(ringMetacarpal - planeOrigin, projectionPlane) + planeOrigin; ringTip = Vector3.ProjectOnPlane(ringTip - planeOrigin, projectionPlane) + planeOrigin; // Limit thumb positions float thumbDistalOverlap = Vector3.Dot(thumbDistal - planeOrigin, projectionPlane); if (thumbDistalOverlap < 0) { thumbDistal += thumbDistalOverlap * projectionPlane; } float thumbTipOverlap = Vector3.Dot(thumbTip - planeOrigin, projectionPlane); if (thumbTipOverlap < 0) { thumbTip += thumbTipOverlap * projectionPlane; } float indexMetric = SegmentDisplacement.SegmentToSegmentDistance(indexMetacarpal, indexTip, thumbDistal, thumbTip); float middleMetric = SegmentDisplacement.SegmentToSegmentDistance(middleMetacarpal, middleTip, thumbDistal, thumbTip); float ringMetric = SegmentDisplacement.SegmentToSegmentDistance(ringMetacarpal, ringTip, thumbDistal, thumbTip); float wipMetric = (indexMetric + middleMetric + ringMetric) / (3.0f); metric = Mathf.Max(0f, wipMetric - 0.01f); return(metric); }
bool ShouldGestureDeactivate(Leap.Hand hand) { bool shouldDeactivate = false; _latestPinchStrength = 1f; if (minDeactivateTimer > MIN_DEACTIVATE_TIME) { var pinchDistance = GetCustomPinchDistance(hand); if (pinchDistance > pinchDeactivateDistance) { shouldDeactivate = true; } } else { minDeactivateTimer += 1; } if (shouldDeactivate) { minReactivateTimer = 0; } return(shouldDeactivate); }
//Recognise current gesture function public string Recognise(Leap.Hand cur_hand) { //Initially assuming no gesture string gesture = "NONE"; //If palm faces camera bool result = checkPalmFacingCamera(cur_hand); if (result) { //Was going to be used for UI gesture = "UI"; } //If making fist bool result_fist = checkFist(cur_hand); if (result_fist) { //Used for shooting gesture = "FIST"; } //Return gesture here return(gesture); //There is a gesture hierarchy of sorts, //If the user is making a fist, we can ignore UI for example }
// Update is called once per frame void Update() { Leap.Hand left = null, right = null; List <Leap.Finger> leftFingers = null, rightFingers = null; controller.CurrentFrame.Hands.ForEach(delegate(Leap.Hand hand) { if (hand.IsLeft) { left = hand; leftFingers = hand.Fingers; } else if (hand.IsRight) { right = hand; rightFingers = hand.Fingers; } }); if (left != null) { if (Vector3.Angle(leftFingers[1].Direction.ToVector3(), left.Direction.ToVector3()) > 120) { transform.position += new Vector3(0, 0, -1); } else if (Vector3.Angle(leftFingers[1].Direction.ToVector3(), left.Direction.ToVector3()) < 50) { transform.position += new Vector3(0, 0, 1); } } }
public bool checkPinch() { //Determine which hand. if (handedness == "Right") { hand = Hands.Right; } else { hand = Hands.Left; } //Check if hand exists if (hand == null) { return(false); } //Get position and value of Pinch bool detected = util.IsPinching(hand); if (detected) { position = util.weightedPos(hand); } return(detected); }
List <float> HandToFloatArray(Leap.Hand h) { List <float> FloatArray = new List <float>(); for (int i = 0; i < 5; i++) { Finger f = h.Fingers[i]; // Debug.Log("PRST : " + f.ToString() + "indeks: " + i); for (int j = 0; j < 4; j++) { // Debug.Log("Kost broj :" + j); Bone b = f.Bone((Bone.BoneType)j); Vector pJoint = b.PrevJoint; Vector nJoint = b.NextJoint; FloatArray.Add(pJoint.x); FloatArray.Add(pJoint.y); FloatArray.Add(pJoint.z); FloatArray.Add(nJoint.x); FloatArray.Add(nJoint.y); FloatArray.Add(nJoint.z); } } return(FloatArray); }
private Node AddChildBone(string fingerType, string boneType, Hand hand, Node parentNode) { Node boneNode = new Node(); boneNode.Name = GetNodeBoneName(fingerType, boneType, hand); parentNode.Children.Add(boneNode); return (boneNode); }
/// <summary> /// Add a new frame Animation channel /// </summary> private void AddNewFrame(Hand hand, Animation anim) { NodeAnimationChannel nodeChannelHand = AssimpUtil.FindNodeAnim(anim, GetNodeHandName(hand.Id.ToString())); var assimpNodeAnimHand = VectorToNode(hand.PalmPosition, anim.DurationInTicks); nodeChannelHand.PositionKeys.Add(assimpNodeAnimHand.Item1); nodeChannelHand.RotationKeys.Add(assimpNodeAnimHand.Item2); foreach (Finger finger in hand.Fingers) { Leap.Bone bone; foreach (Leap.Bone.BoneType boneType in (Leap.Bone.BoneType[])Enum.GetValues(typeof(Leap.Bone.BoneType))) { bone = finger.Bone(boneType); //Fetch the NodeAnim corresponding to the Bone NodeAnimationChannel nodeChannel = AssimpUtil.FindNodeAnim(anim, GetNodeBoneName(finger.Type.ToString(), boneType.ToString(), hand)); var assimpNodeAnim = VectorToNode(bone.NextJoint - bone.PrevJoint, anim.DurationInTicks); //BoneToNode(bone); nodeChannel.PositionKeys.Add(assimpNodeAnim.Item1); nodeChannel.RotationKeys.Add(assimpNodeAnim.Item2); } } }
public Hand makeHand(ref LEAP_HAND hand, Frame owningFrame) { Arm newArm = makeArm(ref hand.arm); Hand newHand = new Hand( (int)owningFrame.Id, (int)hand.id, hand.confidence, hand.grab_strength, hand.grab_angle, hand.pinch_strength, hand.pinch_distance, hand.palm.width, hand.type == eLeapHandType.eLeapHandType_Left, hand.visible_time, newArm, new List<Finger>(5), new Vector(hand.palm.position.x, hand.palm.position.y, hand.palm.position.z), new Vector(hand.palm.stabilized_position.x, hand.palm.stabilized_position.y, hand.palm.stabilized_position.z), new Vector(hand.palm.velocity.x, hand.palm.velocity.y, hand.palm.velocity.z), new Vector(hand.palm.normal.x, hand.palm.normal.y, hand.palm.normal.z), new Vector(hand.palm.direction.x, hand.palm.direction.y, hand.palm.direction.z), newArm.NextJoint //wrist position ); newHand.Fingers.Insert(0, makeFinger(owningFrame, ref hand, ref hand.thumb, Finger.FingerType.TYPE_THUMB)); newHand.Fingers.Insert(1, makeFinger(owningFrame, ref hand, ref hand.index, Finger.FingerType.TYPE_INDEX)); newHand.Fingers.Insert(2, makeFinger(owningFrame, ref hand, ref hand.middle, Finger.FingerType.TYPE_MIDDLE)); newHand.Fingers.Insert(3, makeFinger(owningFrame, ref hand, ref hand.ring, Finger.FingerType.TYPE_RING)); newHand.Fingers.Insert(4, makeFinger(owningFrame, ref hand, ref hand.pinky, Finger.FingerType.TYPE_PINKY)); return newHand; }
// Update is called once per frame void Update() { if (placed) { return; } frame = leapcontroller.Frame(); lHand = Hands.Left; // if there are hands visible in the view. if (lHand != null) { if (util.IsFlatHand(lHand)) { HUDObject.SetActive(true); } else { HUDObject.SetActive(false); } } else { // if no hands are visible in the view, set the HUD inactive HUDObject.SetActive(false); } }
//Update the hand public void UpdateHand(Leap.Hand hand) { if (!hand.IsValid) { return; } //Refresh leap hand data this.hand = hand; //Set handObject position //Reverse z coordinate handObject.transform.position = new Vector3(hand.PalmPosition.x, hand.PalmPosition.y, -hand.PalmPosition.z); //Set last hand position lastPosition = position; //Set hand position position = handObject.transform.position; //Set last hand speed lastSpeed = speed; //Set hand speed speed = new Vector3(hand.PalmVelocity.x, hand.PalmVelocity.y, -hand.PalmVelocity.z); //Refresh leap finger data UpdateFingers(); }
private char DoASLTest_B(Leap.Hand hand) { float fingerThreshold = 1400; Leap.FingerList fingers = hand.Fingers; Leap.Finger pinky = fingers[(int)Leap.Finger.FingerType.TYPE_PINKY]; Leap.Finger ring = fingers[(int)Leap.Finger.FingerType.TYPE_RING]; Leap.Finger middle = fingers[(int)Leap.Finger.FingerType.TYPE_MIDDLE]; Leap.Finger index = fingers[(int)Leap.Finger.FingerType.TYPE_INDEX]; Leap.Finger thumb = fingers[(int)Leap.Finger.FingerType.TYPE_THUMB]; Vector3 pinkyPos = ToVector3(pinky.Bone(Leap.Bone.BoneType.TYPE_INTERMEDIATE).NextJoint); Vector3 ringPos = ToVector3(ring.Bone(Leap.Bone.BoneType.TYPE_INTERMEDIATE).NextJoint); Vector3 middlePos = ToVector3(middle.Bone(Leap.Bone.BoneType.TYPE_INTERMEDIATE).NextJoint); Vector3 indexPos = ToVector3(index.Bone(Leap.Bone.BoneType.TYPE_INTERMEDIATE).NextJoint); if ((pinkyPos - ringPos).sqrMagnitude < fingerThreshold && (ringPos - middlePos).sqrMagnitude < fingerThreshold && (middlePos - indexPos).sqrMagnitude < fingerThreshold) { return('B'); } return(INVALID_ASL_LETTER); }
//Test the final posture of the hand to end the gesture protected override void TestEndGesture(Hand hand) { if (hand.PalmPosition.y-InitialPosition >= 150) { FinishGesture(); } }
private static IJoint BuildHand(Hand hand, IJoint wrist, int side) { var handJoint = new OrientedJoint(); if (hand.IsValid) { var palmNormal = hand.PalmNormal; var handPosition = hand.PalmPosition; handJoint.Orientation = new Vector4(10 * palmNormal.x, 10 * palmNormal.y, 10 * palmNormal.z, 0); handJoint.Point = new Vector3(0, 0, -100); var fingers = hand.Fingers; foreach (var t in fingers) { var normal = t.Direction; var position = t.TipPosition - handPosition; handJoint.AddChild(CreateFinger(position, normal, FingerType2JointType(t.Type(), side))); } handJoint.Valid = true; } return handJoint; }
//Needs tested. Checks for a thumbs up pose. public bool checkThumbsUp(Leap.Hand hand) { foreach (Leap.Finger f in hand.Fingers) { if (f.Type == Leap.Finger.FingerType.TYPE_THUMB) { if (f.IsExtended && checkDirectionUp(f)) { continue; } else { return(false); } } else { if (f.IsExtended && checkDirectionUp(f)) { return(false); } else { continue; } } } return(true); }
//Checks to see if a swipe has occured recently. //Uses recent frame information and the users hand public bool isSwiping(Leap.Hand hand, Queue <FrameInformation> framesQueue) { if (framesQueue.Count < 50) { return(false); } FrameInformation[] frames = framesQueue.ToArray(); List <float> accelMag = new List <float>(); //if not enough fingers extended no swipe if (Extended(hand.Fingers) >= 4) { //Fetch the accel magnitude of recent and current frames Vector3 accel = (hand.PalmVelocity.ToVector3() - frames[frames.Length - 2].hand.palmVelocity); accelMag.Add(Vector3.Project(accel, hand.PalmNormal.ToVector3()).magnitude); accelMag[0] *= Mathf.Sign(Vector3.Dot(accel, hand.PalmNormal.ToVector3())); for (int i = frames.Length - 1; i > frames.Length - 7; --i) { accel = (frames[i].hand.palmVelocity - frames[frames.Length - 2].hand.palmVelocity); accelMag.Add(Vector3.Project(accel, frames[i].hand.palmNormal).magnitude); accelMag[accelMag.Count - 1] *= Mathf.Sign(Vector3.Dot(accel, frames[i].hand.palmNormal)); } //Grab the roll of the hand float handRoll = Mathf.Abs(hand.PalmNormal.Roll); return((handRoll > 1.35 && accelMag[1] < -0.3f && accelMag[0] < accelMag[1] && accelMag[2] > accelMag[1]) ? true : false); } return(false); }
bool ShouldGestureActivate(Leap.Hand hand) { bool shouldActivate = false; _latestPinchStrength = 0f; bool wasEligibleLastCheck = _isGestureEligible; _isGestureEligible = false; // Can only activate a pinch if we haven't already activated a pinch very recently. if (minReactivateTimer > MIN_REACTIVATE_TIME) { shouldActivate = CheckHandForActivation(hand, wasEligibleLastCheck); } else { minReactivateTimer += 1; } if (shouldActivate) { minDeactivateTimer = 0; } return(shouldActivate); }
void OnCollisionEnter(Collision collision) { if (canCollide) { var parent = GetParent("RigidHand(Clone)", collision.collider.transform); if (parent == null) { return; } LM.Hand hand = parent.GetComponent <RigidHand>().GetLeapHand(); Marker marker = this.GetComponentInParent <Marker>(); logger.Debug("Collision"); if (hand.IsLeft == marker.IsLeft) { logger.Debug("Collision with correct hand"); if (OnMarkerCollision != null) { OnMarkerCollision(marker, gesture, hand); } } } }
// Update is called once per frame void Update() { Leap.Hand left = null, right = null; List <Leap.Finger> leftFingers = null, rightFingers = null; controller.CurrentFrame.Hands.ForEach(delegate(Leap.Hand hand) { if (hand.IsLeft) { left = hand; leftFingers = hand.Fingers; } else if (hand.IsRight) { right = hand; rightFingers = hand.Fingers; } }); if (right != null) { if (previousDownVelocity > -2 && rightFingers[1].TipVelocity.y < -2 && Vector3.Angle(rightFingers[1].Direction.ToVector3(), right.Direction.ToVector3()) < 60 && Vector3.Angle(rightFingers[2].Direction.ToVector3(), right.Direction.ToVector3()) > 120 && Vector3.Angle(rightFingers[3].Direction.ToVector3(), right.Direction.ToVector3()) > 120) { ToggleMenu(); } previousDownVelocity = rightFingers[1].TipVelocity.y; } }
public HandRepresentation(int handID, Hand hand, Chirality chirality, ModelType modelType) { HandID = handID; this.MostRecentHand = hand; this.RepChirality = chirality; this.RepType = modelType; }
// Update is called once per frame void Update() { controller = new Leap.Controller(); Leap.Frame frame = controller.Frame(); List <Leap.Hand> hands = frame.Hands; Leap.Hand fristHand = hands[0]; position = hands[0].PalmPosition; pos = Leap.Unity.UnityVectorExtension.ToVector3(position); // Attach to the palm // Vive Tracker //Vector3 pos = new Vector3(ViveHand.transform.position.x - 0.2f, ViveHand.transform.position.y + 1.0f, ViveHand.transform.position.z - 0.5f); //Vector3 pos = new Vector3(ViveHand.transform.position.x, ViveHand.transform.position.y, ViveHand.transform.position.z); transform.position = pos; //if (!pos.Equals(UnityEngine.Vector3.zero)) //{ // // If non-zero, orientate to the hand surface // Vector3 dir = new Vector3(hand.Direction.x, hand.Direction.y, 0.0f); // Vector3 norm =new Vector3(hand.PalmNormal.x, hand.PalmNormal.y, 0.0f); // transform.rotation = Quaternion.LookRotation(dir, norm); //} }
/// <summary> /// Build a Node hierachy into the scene property 'mainScene' from a Hand object /// </summary> /// <param name="hand"></param> private void CreateNodeHierarchy(Hand hand, Scene handScene) { Node rootNode = handScene.RootNode = new Node(); Node handNode = new Node(); handNode.Name = GetNodeHandName(hand.Id.ToString()); rootNode.Children.Add(handNode); NodeAnimationChannel bonetest = new NodeAnimationChannel(); bonetest.NodeName = GetNodeHandName(hand.Id.ToString()); handScene.Animations[0].NodeAnimationChannels.Add(bonetest); foreach (Finger finger in hand.Fingers) { Node fingerNode = handNode; foreach (Leap.Bone.BoneType boneType in (Leap.Bone.BoneType[])Enum.GetValues(typeof(Leap.Bone.BoneType))) { string fingerType = finger.Type.ToString(); //Add a node hierarchy fingerNode = AddChildBone(fingerType, boneType.ToString(), hand, fingerNode); //Fill the NodeAnimChannel NodeAnimationChannel bone = new NodeAnimationChannel(); bone.NodeName = GetNodeBoneName(fingerType, boneType.ToString(), hand); handScene.Animations[0].NodeAnimationChannels.Add(bone); } } }
// Update is called once per frame void FixedUpdate() { Leap.Hand mHand = myLeapManagerInstance.frontmostHand(); if (mHand.IsValid) { if (!swordUp) { audio.Play(); } swordUp = true; } else { if (swordUp) { AudioSource.PlayClipAtPoint(swordSheath, transform.position, 0.25f); } swordUp = false; } Vector3 targetPos = getTargetPos(mHand); Quaternion targetRot = getTargetRot(mHand); //moveWithForce(targetPos); moveWithMovePos(targetPos, targetRot); }
private IEnumerator leftHandWatcher() { while (true) { if (leftHandModel != null) { leftHand = leftHandModel.GetLeapHand(); if (leftHand != null) { //if (leftHand.GrabStrength >= 0.85f) Debug.Log("Left Grabbing"); if (leftHandState != 0 && leftHand.PinchStrength >= pinchStrengthForce) { //Debug.Log("Left Pinching"); leftHandState = 1; } else if (leftHand.GrabStrength <= grabStrengthForce) { //Debug.Log("Left AllExtend"); leftHandState = 2; } else { offset = Vector3.zero; leftHandState = 0; if (workstationActivated) { dynamicUI.GetComponent <WorkstationBehaviourExample>().DeactivateWorkstation(); workstationActivated = false; } } if (leftHandState == 2) { if (leftHand.PalmVelocity.z >= onoffVelocity) { //Debug.Log("Left Window TurnOff"); leftHandState = 3; } else if (leftHand.PalmVelocity.z <= -onoffVelocity) { //Debug.Log("Left Window TurnOn"); leftHandState = 4; } if (leftHand.PalmVelocity.x <= -onoffVelocity) { leftHandState = 5; //Debug.Log("Left"); } else if (leftHand.PalmVelocity.x >= onoffVelocity) { leftHandState = 6; } } } } yield return(new WaitForSeconds(0.1f)); } }
//Test the initial posture of the hand to start the gesture protected override void TestInitialGesture(Hand hand) { InitialPosition = hand.PalmPosition.x; PreviousHand = hand; ReceiveBeginningLeftMoveEvent(); }
public HandProxy(HandPool parent, Hand hand, Chirality repChirality, ModelType repType) : base(hand.Id, hand, repChirality, repType) { this.parent = parent; this.RepChirality = repChirality; this.RepType = repType; this.MostRecentHand = hand; }
float GetCustomPinchDistance(Leap.Hand hand) { float pinchDistance = PinchSegmentToSegmentDisplacement(hand).magnitude; pinchDistance -= 0.01f; pinchDistance = Mathf.Max(0f, pinchDistance); return(pinchDistance); }
List <Leap.Hand> FloatArrayToHands(List <float> FloatArray, List <GameObject> zgloboviIKostii) { List <Leap.Hand> hands = new List <Hand>(); int z = 0; int handsCount = (int)FloatArray[z]; z++; for (int k = 0; k < handsCount; k++) { Leap.Hand h = new Leap.Hand(); float leftRight = FloatArray[z]; z++; if (leftRight == 0) { h.IsLeft = true; } else { h.IsLeft = false; } for (int i = 0; i < 5; i++) { Finger f = h.Fingers[i]; f.TipPosition.x = FloatArray[z]; f.TipPosition.y = FloatArray[z + 1]; f.TipPosition.z = FloatArray[z + 2]; z += 3; for (int j = 0; j < 4; j++) { Bone b = f.Bone((Bone.BoneType)j); b.PrevJoint = new Vector(FloatArray[z], FloatArray[z + 1], FloatArray[z + 2]); z += 3; b.NextJoint = new Vector(FloatArray[z], FloatArray[z + 1], FloatArray[z + 2]); z += 3; } } h.PalmPosition.x = FloatArray[z]; h.PalmPosition.y = FloatArray[z + 1]; h.PalmPosition.z = FloatArray[z + 2]; z += 3; hands.Add(h); } return(hands); }
FrameInformation fetchFrameInformation() { FrameInformation frameInfo = new FrameInformation(); frameInfo.grabHeld = grabHeld; frameInfo.pinchHeld = pinchHeld; foreach (Leap.Finger f in hand.Fingers) { FingerInformation fingerInfo = new FingerInformation(); fingerInfo.isExtended = f.IsExtended; fingerInfo.direction = f.Direction.ToVector3(); fingerInfo.padDirection = Vector3.Cross(fingerInfo.direction, Vector3.Cross(fingerInfo.direction, f.bones[1].Direction.ToVector3())); fingerInfo.tipPosition = f.TipPosition.ToVector3(); fingerInfo.tipVelocity = f.TipVelocity.ToVector3(); switch (f.Type) { case Leap.Finger.FingerType.TYPE_INDEX: frameInfo.index = fingerInfo; break; case Leap.Finger.FingerType.TYPE_MIDDLE: frameInfo.middle = fingerInfo; break; case Leap.Finger.FingerType.TYPE_RING: frameInfo.ring = fingerInfo; break; case Leap.Finger.FingerType.TYPE_PINKY: frameInfo.pinky = fingerInfo; break; case Leap.Finger.FingerType.TYPE_THUMB: frameInfo.thumb = fingerInfo; break; } } if (handedness == "Right") { hand = Hands.Right; } else { hand = Hands.Left; } HandInformation handInfo = new HandInformation(); handInfo.direction = hand.Direction.ToVector3(); handInfo.pitch = hand.Direction.Pitch; handInfo.roll = hand.Direction.Roll; handInfo.yaw = hand.Direction.Yaw; handInfo.palmPosition = hand.PalmPosition.ToVector3(); handInfo.palmVelocity = hand.PalmVelocity.ToVector3(); handInfo.palmNormal = hand.PalmNormal.ToVector3(); handInfo.rotation = hand.Rotation.ToQuaternion(); frameInfo.hand = handInfo; return(frameInfo); }
protected Finger FindFingerByType(Hand hand, Finger.FingerType type) { foreach (var finger in hand.Fingers) { if (finger.Type() == type) return finger; } return null; }
/* ========================= Initialize Tracking Algorithms ============================ */ /* Method for the Distance Between Palm and Pointer */ private static void OnLeapMotionUpdate(Leap.Hand hand) { // Get Instance InputManager IM = _instance; if (IM == null) { return; } // Complete First Pass FingerLift[] fingerTest = IM.RetrieveFingerLift(hand); ASLTest firstPassResults = IM.FirstPassAlgorithm(fingerTest); // Call Similarity Handler IM.UpdateCurrentSimilarity(firstPassResults); /*if(IM.similarityHandler != null) * { * IM.similarityHandler(firstPassResults); * }*/ if (firstPassResults == ASLTest.INVALID_ASL_TEST) { IM.UpdateCurrentLetter(INVALID_ASL_LETTER); return; } // Complete Second Pass char secondPassResults = IM.SecondPassAlgorithm(firstPassResults, hand); // Determine if Successful bool finalResults = (secondPassResults >= 'A' && secondPassResults <= 'Z') || (secondPassResults >= 'a' && secondPassResults <= 'z'); if (IM.lastResult != secondPassResults) { IM.lastResult = secondPassResults; IM.lastLetterTime = DateTime.Now.Ticks; } // Call Letter Handler if (finalResults) { if (((DateTime.Now.Ticks - IM.lastLetterTime) / TimeSpan.TicksPerMillisecond) >= (IM.dwellTime * 1000)) { IM.UpdateCurrentLetter(secondPassResults); } else { IM.UpdateCurrentLetter(INVALID_ASL_LETTER); } } else { IM.UpdateCurrentLetter(INVALID_ASL_LETTER); } }
// Use this for initialization void Start() { theHand = GameObject.FindGameObjectWithTag("handControl").GetComponent <HandController>(); Leap.Frame frame = theHand.GetFrame(); // controller is a Controller object Leap.HandList hands = frame.Hands; firstHand = hands[0]; Debug.Log("starting"); }
private bool ShouldTriggerGrab(Leap.Hand hand) { float handAngle = GetAngle(hand); float clampedHandAngle = Mathf.Clamp(handAngle, clickAngle, 180); GrabStrength = ScreenControlUtility.MapRangeToRange(clampedHandAngle, clickAngle, 180, 1, 0); return(handAngle < clickAngle); }
static Vector3 PinchSegmentToSegmentDisplacement(Leap.Hand hand) { Vector3 indexDistal = hand.GetIndex().bones[3].PrevJoint.ToVector3(); Vector3 indexTip = hand.GetIndex().TipPosition.ToVector3(); Vector3 thumbDistal = hand.GetThumb().bones[3].PrevJoint.ToVector3(); Vector3 thumbTip = hand.GetThumb().TipPosition.ToVector3(); return(SegmentToSegmentDisplacement(indexDistal, indexTip, thumbDistal, thumbTip)); }
void createUI(Leap.Hand right_hand, Vector3 relPosBetweenHands) { initialAlpha = 0.0f; Vector3 r_palm_Pos = right_hand.PalmPosition.ToVector3(); Vector3 uiPos = camera_.transform.position + (camera_.forward * .503f); created_ui = (GameObject)Instantiate(UI, uiPos, Quaternion.identity); created_ui.GetComponent <Renderer>().material.color = new Color(Color.green.r, Color.green.g, Color.green.b, initialAlpha); }
/* * IEnumerator BeklemeIncongruent() * { * int randomNumber = UnityEngine.Random.Range(0, 4); * int randomNumberSecond = UnityEngine.Random.Range(0, 4); * * yield return new WaitForSeconds(2.5f); * GameObject.Find("Numerator").GetComponent<TextMesh>().text = digits[randomNumber]; * isTiming = true; * // GestureIncongruent(); * yield return new WaitUntil(() => DigitDetector() == randomNumber); * Debug.Log(DigitDetector() + " Reaction time: " + reactionTimer + " ms"); * GameObject.Find("Numerator").GetComponent<TextMesh>().text = "TRUE"; * yield return new WaitForSeconds(0.2f); * GameObject.Find("Numerator").GetComponent<TextMesh>().text = ""; * isTiming = false; * reactionTimer = 0; * * yield return new WaitForSeconds(2.5f); * GameObject.Find("Numerator").GetComponent<TextMesh>().text = digits[randomNumberSecond]; * isTiming = true; * yield return new WaitUntil(() => DigitDetector() == randomNumberSecond); * Debug.Log(DigitDetector() + " Reaction timeSecond: " + reactionTimer + " ms"); * GameObject.Find("Numerator").GetComponent<TextMesh>().text = "TRUE"; * yield return new WaitForSeconds(0.2f); * GameObject.Find("Numerator").GetComponent<TextMesh>().text = ""; * isTiming = false; * reactionTimer = 0; * } */ public bool PostureDetector() { _current = _controller.Frame(); var rightHandPosture = new Vector3(); var leftHandPosture = new Vector3(); var isRHandPostureCounting = false; var isLHandPostureCounting = false; //TODO: is this part necessary for this method if (_current.Hands.Count == 1) { if (_current.Hands[0].IsRight) { _handRight = _current.Hands[0]; _handLeft = null; } else if (_current.Hands[0].IsLeft) { _handLeft = _current.Hands[0]; _handRight = null; } } else if (_current.Hands.Count == 2) { _handRight = _current.Hands[0]; _handLeft = _current.Hands[1]; } else if (_current.Hands.Count == 0) { _handRight = null; _handLeft = null; } if (_handRight != null) { rightHandPosture = _handRight.Basis.yBasis.ToVector3(); } if (_handLeft != null) { leftHandPosture = _handLeft.Basis.yBasis.ToVector3(); } if (rightHandPosture.y >= 0) { isRHandPostureCounting = true; } if (leftHandPosture.y >= 0) { isLHandPostureCounting = true; } return(isLHandPostureCounting && isRHandPostureCounting); }
void FollowHand(IVIHand ivihand) { Leap.Hand hand = ivihand.LeapHand; Vector3 palmPos = hand.PalmPosition.ToVector3(); Vector3 palmNorm = hand.PalmNormal.ToVector3(); float palmRot = .02f + transform.localScale.y / 2; transform.position = initialPos + palmNorm * palmRot + palmPos; transform.rotation = hand.Basis.rotation.ToQuaternion(); }
/** Calls Updates in IHandModels that are part of this HandRepresentation */ public override void UpdateRepresentation(Hand hand) { base.UpdateRepresentation(hand); if (handModels != null) { for (int i = 0; i < handModels.Count; i++) { handModels[i].SetLeapHand(hand); handModels[i].UpdateHand(); } } }
//Test gesture and throw an event if the gesture is validated public override void TestGesture(Hand hand) { //throw an event if the posture is verified if (TestPosture(hand)) { if (GestureRecognized != null) { GestureRecognized(); } } }
// Constructor for LeapFrame public HandData(Hand hand) { m_id = hand.Id; m_fingers = new List<FingerData>(); foreach (Finger f in hand.Fingers) { m_fingers.Add(new FingerData(f)); } m_isFrontmost = (hand.Id == hand.Frame.Hands.Frontmost.Id); m_palmPosition = hand.PalmPosition; m_isValid = hand.IsValid; }
public HandProxy(HandPool parent, IHandModel handModel, Hand hand) : base(hand.Id) { this.parent = parent; this.handModel = handModel; // Check to see if the hand model has been initialized yet if (handModel.GetLeapHand() == null) { handModel.SetLeapHand(hand); handModel.InitHand(); } else { handModel.SetLeapHand(hand); } handModel.BeginHand(); }
//get latest frame called each second public static void Update() { if(_controller != null) { Frame lastFrame = _frame == null ? Frame.Invalid : _frame; _frame = _controller.Frame(); if(_frame != null) { if(_frame.Hands.Count > 0) { _hand = _frame.Hands[0]; } } } }
//Test gesture and throw an event if the gesture is validated public override void TestGesture(Hand hand) { //verify if it is the first frame of the position if (!IsRunning) { TestInitialGesture(hand); } else { //verify the dynamic of the gesture if (CurrentNbOfFrame <= MinNbOfFrame) { if (TestDynamic(hand)) { PreviousHand = hand; CurrentNbOfFrame++; } else { IsRunning = false; CurrentNbOfFrame = 0; } } //verify the dynamic of the gesture or the end of gesture else if (CurrentNbOfFrame <= MaxNbOfFrame) { if (TestDynamic(hand)) { PreviousHand = hand; CurrentNbOfFrame++; TestEndGesture(hand); } else { IsRunning = false; CurrentNbOfFrame = 0; } } //case if the gesture is too long else { IsRunning = false; CurrentNbOfFrame = 0; } } }
/*--------------------------------------------------------------------------------------------*/ private void UpdateForFinger(Hand pLeapHand, Finger.FingerType pLeapFingerType) { Finger leapFinger = LeapUtil.GetValidFinger(pLeapHand, pLeapFingerType); if ( leapFinger == null ) { UpdateForNull(); return; } Bone bone = leapFinger.Bone(Bone.BoneType.TYPE_DISTAL); //GC_ALLOC IsAvailable = true; Position = leapFinger.TipPosition.ToUnityScaled(); //GC_ALLOC Rotation = LeapUtil.CalcQuaternion(bone.Basis); //GC_ALLOC Size = leapFinger.Width*SizeScaleFactor; }
public static void Update() { if( m_controller != null ) { Frame lastFrame = m_Frame == null ? Frame.Invalid : m_Frame; m_Frame = m_controller.Frame(); if (m_Frame != null) { if (m_Frame.Hands.Count > 0) { m_Hand = m_Frame.Hands[0]; } fingerCount = m_Frame.Fingers.Count; } } }
/** * MakeHandRepresentation receives a Hand and combines that with an IHandModel to create a HandRepresentation * @param hand The Leap Hand data to be drive an IHandModel * @param modelType Filters for a type of hand model, for example, physics or graphics hands. */ public override HandRepresentation MakeHandRepresentation(Hand hand, ModelType modelType) { Chirality handChirality = hand.IsRight ? Chirality.Right : Chirality.Left; HandRepresentation handRep = new HandProxy(this, hand, handChirality, modelType); for (int i = 0; i < ModelPool.Count; i++) { ModelGroup group = ModelPool[i]; if (group.IsEnabled) { IHandModel model = group.TryGetModel(handChirality, modelType); if (model != null) { handRep.AddModel(model); modelToHandRepMapping.Add(model, handRep); } } } activeHandReps.Add(handRep); return handRep; }
/*--------------------------------------------------------------------------------------------*/ public void UpdateWithHand(Hand pLeapHand) { if ( pLeapHand == null ) { UpdateForNull(); return; } if ( vLeapFingerType != null ) { UpdateForFinger(pLeapHand, (Finger.FingerType)vLeapFingerType); return; } if ( vIsPalm ) { UpdateForPalm(pLeapHand); return; } throw new Exception("Unhandled CursorType: "+Type); }
public static void Update() { if( m_controller != null ) { Frame lastFrame = m_Frame == null ? Frame.Invalid : m_Frame; m_Frame = m_controller.Frame(); if (m_Frame != null) { if (m_Frame.Hands.Count > 0) { m_Hand = m_Frame.Hands[0]; normal = m_Hand.PalmNormal; direction = m_Hand.Direction; } } } }
// Update is called once per frame void Update() { transform.RotateAround(new Vector3(0.0f,1.0f,0.0f),angle); Leap.Frame frame = controller.Frame(); guiFrame=frame; if (!frame.Hands.Empty) { hand0 = frame.Hands[0]; hand1 = frame.Hands[1]; Leap.FingerList fingers = hand0.Fingers; if (!fingers.Empty) { Leap.Finger firstfinger = fingers[0]; if ((hand1.Fingers.Count) >=3 ){ mustPause=true; } mustPause=false; if (!hand1.IsValid ||(hand1.IsValid && hand1.Fingers.Count<=2) ){ if (mustPause==false && frame.Hands[0].Id != hand1ID){ // (*)<-- //if (scratch==true) if (audio.pitch > 0.0f) audio.pitch-=0.010f; if (hand0.PalmPosition.x>0 ){ float moveStraightY = hand0.PalmPosition.y; if (moveStraightY >190) angle = 2.0f; if (moveStraightY >=130 && moveStraightY<190) { moveStraightY/=180; if (moveStraightY>1) moveStraightY=1; angle = moveStraightY; } else { if (angle > 0.0f) angle -=0.30f; if (angle <= 0.0f) angle =0.0f; } } } } } } else { if (angle<2.0f) angle +=0.086f; } }
public static Hand MakeTestHand(int frameId, int handId, bool isLeft){ List<Finger> fingers = new List<Finger>(5); fingers.Add(MakeThumb (frameId, handId, isLeft)); fingers.Add(MakeIndexFinger (frameId, handId, isLeft)); fingers.Add(MakeMiddleFinger (frameId, handId, isLeft)); fingers.Add(MakeRingFinger (frameId, handId, isLeft)); fingers.Add( MakePinky (frameId, handId, isLeft)); Vector armWrist = new Vector(-7.05809944059f, 4.0f, 50.0f); Vector elbow = armWrist + 250f * Vector.Backward; // Adrian: The previous "armBasis" used "elbow" as a translation component. Arm arm = new Arm(elbow, armWrist,(elbow + armWrist)/2, Vector.Forward, 250f, 41f, LeapQuaternion.Identity); Hand testHand = new Hand(frameId, handId, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 85f, isLeft, 0.0f, arm, fingers, new Vector (0,0,0), new Vector(0,0,0), new Vector(0,0,0), Vector.Down, Vector.Forward, new Vector(-4.36385750984f, 6.5f, 31.0111342526f) ); LeapTransform restPosition = LeapTransform.Identity; //restPosition.rotation = RotationFromTo(Vector.Up, Vector.Left).Multiply(RotationFromTo(Vector.Up, Vector.Left)); restPosition.rotation = AngleAxis(180 * Constants.DEG_TO_RAD, Vector.Forward); if(isLeft){ restPosition.translation = new Vector(80f, 120f, 0f); } else { restPosition.translation = new Vector(-80f, 120f, 0f); restPosition.MirrorX(); } return testHand.TransformedCopy(restPosition); }
public Hand makeHand(ref LEAP_HAND hand, Frame owningFrame) { LEAP_BONE arm = LeapC.PtrToStruct<LEAP_BONE>(hand.arm); Arm newArm = makeArm(ref arm); LEAP_PALM palm = LeapC.PtrToStruct<LEAP_PALM>(hand.palm); Hand newHand = new Hand( (int)owningFrame.Id, (int)hand.id, hand.confidence, hand.grab_strength, hand.grab_angle, hand.pinch_strength, hand.pinch_distance, palm.width, hand.type == eLeapHandType.eLeapHandType_Left, hand.visible_time, newArm, new List<Finger>(5), new Vector(palm.position.x, palm.position.y, palm.position.z), new Vector(palm.stabilized_position.x, palm.stabilized_position.y, palm.stabilized_position.z), new Vector(palm.velocity.x, palm.velocity.y, palm.velocity.z), new Vector(palm.normal.x, palm.normal.y, palm.normal.z), new Vector(palm.direction.x, palm.direction.y, palm.direction.z), newArm.NextJoint //wrist position ); LEAP_DIGIT thumbDigit = LeapC.PtrToStruct<LEAP_DIGIT>(hand.thumb); newHand.Fingers.Insert(0, makeFinger(owningFrame, ref hand, ref thumbDigit, Finger.FingerType.TYPE_THUMB)); LEAP_DIGIT indexDigit = LeapC.PtrToStruct<LEAP_DIGIT>(hand.index); newHand.Fingers.Insert(1, makeFinger(owningFrame, ref hand, ref indexDigit, Finger.FingerType.TYPE_INDEX)); LEAP_DIGIT middleDigit = LeapC.PtrToStruct<LEAP_DIGIT>(hand.middle); newHand.Fingers.Insert(2, makeFinger(owningFrame, ref hand, ref middleDigit, Finger.FingerType.TYPE_MIDDLE)); LEAP_DIGIT ringDigit = LeapC.PtrToStruct<LEAP_DIGIT>(hand.ring); newHand.Fingers.Insert(3, makeFinger(owningFrame, ref hand, ref ringDigit, Finger.FingerType.TYPE_RING)); LEAP_DIGIT pinkyDigit = LeapC.PtrToStruct<LEAP_DIGIT>(hand.pinky); newHand.Fingers.Insert(4, makeFinger(owningFrame, ref hand, ref pinkyDigit, Finger.FingerType.TYPE_PINKY)); return newHand; }
private bool CheckTwoHandGestures(Hand leftHand, Hand rightHand, Action<IEnumerable<Result>> fireNewMotions) { var leftHandOld = _startFrame.Hands.Find(h => h.IsLeft); var rightHandOld = _startFrame.Hands.Find(h => h.IsRight); var rightToLeftOld = leftHandOld.PalmPosition - rightHandOld.PalmPosition; var center = rightHandOld.StabilizedPalmPosition + (rightToLeftOld) /2; var cmd = new ScaleAndRotate { Scale = (leftHand.PalmPosition - rightHand.PalmPosition).MagnitudeSquared / (rightToLeftOld).MagnitudeSquared, Center = center, Rotation = Quaternion.Inverse(rightHandOld.Rotation.ToBetterQuaternion()) * rightHand.Rotation.ToBetterQuaternion(), LeftHand = leftHand.PalmPosition, RightHand = rightHand.PalmPosition }; var result = new Result(cmd, 0.9); fireNewMotions(new List<Result> {result}); return true; }
/*--------------------------------------------------------------------------------------------*/ internal void Rebuild(Hand pLeapHand) { if ( pLeapHand == null ) { IsAvailable = false; Position = Vector3.zero; Rotation = Quaternion.identity; Radius = 0; NavigateBackStrength = 0; DisplayStrength = 0; return; } IsAvailable = true; Position = pLeapHand.PalmPosition.ToUnityScaled(); Rotation = LeapUtil.CalcQuaternion(pLeapHand.Basis); //GC_ALLOC Radius = 0.01f; FingerList leapFingers = pLeapHand.Fingers; //GC_ALLOC for ( int i = 0 ; i < leapFingers.Count ; i++ ) { Finger leapFinger = leapFingers[i]; //GC_ALLOC if ( leapFinger == null || !leapFinger.IsValid ) { continue; } Vector3 palmToFinger = leapFinger.TipPosition.ToUnityScaled()-Position; //GC_ALLOC Bone bone = leapFinger.Bone(Bone.BoneType.TYPE_DISTAL); //GC_ALLOC Quaternion boneRot = LeapUtil.CalcQuaternion(bone.Basis); //GC_ALLOC Radius = Math.Max(Radius, palmToFinger.sqrMagnitude); Rotation = Quaternion.Slerp(Rotation, boneRot, 0.1f); } Radius = (float)Math.Sqrt(Radius); Position += Rotation*Vector3.down*vSettings.DistanceFromPalm*Radius; NavigateBackStrength = pLeapHand.GrabStrength/vSettings.NavBackGrabThreshold; NavigateBackStrength = Mathf.Clamp(NavigateBackStrength, 0, 1); DisplayStrength = Vector3.Dot(pLeapHand.PalmNormal.ToUnity(), vSettings.PalmDirection); DisplayStrength = Mathf.Clamp((DisplayStrength-0.7f)/0.25f, 0, 1); }
/** * MakeHandRepresentation receives a Hand and combines that with an IHandModel to create a HandRepresentation * @param hand The Leap Hand data to be drive an IHandModel * @param modelType Filters for a type of hand model, for example, physics or graphics hands. */ public override HandRepresentation MakeHandRepresentation(Hand hand, ModelType modelType) { HandRepresentation handRep = null; for (int i = 0; i < ModelPool.Count; i++) { IHandModel model = ModelPool[i]; bool isCorrectHandedness; Chirality handChirality = hand.IsRight ? Chirality.Right : Chirality.Left; isCorrectHandedness = model.Handedness == handChirality; if (!EnforceHandedness || model.Handedness == Chirality.Either) { isCorrectHandedness = true; } bool isCorrectModelType; isCorrectModelType = model.HandModelType == modelType; if (isCorrectModelType && isCorrectHandedness) { ModelPool.RemoveAt(i); handRep = new HandProxy(this, model, hand); break; } } return handRep; }
/// <summary> /// Builds the hand. /// </summary> /// <returns>The hand.</returns> /// <param name="hand">Hand.</param> /// <param name="side">Side.</param> private static IList<IJoint> BuildHand(Hand hand, int side) { var handJoint = new OrientedJoint(); if (!hand.IsValid) { return new IJoint[]{handJoint}; } var palmNormal = hand.PalmNormal; var handPosition = hand.PalmPosition; handJoint.Orientation = new Vector4(palmNormal.x, palmNormal.y, palmNormal.z, 0); handJoint.Point = new Vector3(0, 0, -100); var joints = new List<IJoint> { handJoint }; var fingers = hand.Fingers; joints.AddRange(from t in fingers let normal = t.Direction let position = t.TipPosition - handPosition select CreateFinger(position, normal, FingerType2JointType(t.Type(), side))); handJoint.Valid = true; return joints; }
public static Hand MakeTestHand(int frameId, int handId, bool isLeft) { FingerList fingers = new FingerList(5); fingers.Add(MakeThumb (frameId, handId)); fingers.Add(MakeIndexFinger (frameId, handId)); fingers.Add(MakeMiddleFinger (frameId, handId)); fingers.Add(MakeRingFinger (frameId, handId)); fingers.Add( MakePinky (frameId, handId)); Vector armWrist = new Vector(-7.05809944059f, 4.0f, 50.0f); Vector elbow = armWrist + 250f * Vector.Backward; Matrix armBasis = new Matrix(Vector.Right, Vector.Down, Vector.Forward); Arm arm = new Arm(elbow,armWrist,(elbow + armWrist)/2, Vector.Forward, 250f, 41f, Bone.BoneType.TYPE_DISTAL, armBasis); Hand testHand = new Hand(frameId, handId, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 85f, isLeft, 0.0f, arm, fingers, new Vector (0,0,0), new Vector(0,0,0), new Vector(0,0,0), Vector.Down, Vector.Backward, new Vector(-4.36385750984f, 6.5f, 31.0111342526f) ); if(isLeft){ return testHand; } else { Matrix leftToRight = new Matrix(Vector.Right, Vector.Up, Vector.Forward); return testHand.TransformedCopy(leftToRight); } }