Tanoda
InteractionHand.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
12using Leap.Unity.Space;
13using Leap.Unity.Query;
14using System;
15using System.Collections;
16using System.Collections.Generic;
17using UnityEngine;
19
20namespace Leap.Unity.Interaction {
21
23
24 [DisallowMultipleComponent]
26
27 #region Inspector
28
29 [SerializeField]
30 private LeapProvider _leapProvider;
31
32 [Header("Hand Configuration")]
33
34 [Tooltip("Should the data for the underlying Leap hand come from the player's left "
35 + "hand or their right hand? Alternatively, you can set this mode to Custom "
36 + "to specify accessor functions manually via script (recommended for advanced "
37 + "users only).")]
38 [SerializeField, EditTimeOnly]
39 private HandDataMode _handDataMode;
41 get { return _handDataMode; }
42 set {
43 // TODO: Do validation if this is modified!
44 _handDataMode = value;
45 }
46 }
47
54 public bool[] enabledPrimaryHoverFingertips = new bool[5] { true, true, true, false, false };
55
56 #endregion
57
58 #region Hand Data
65 get { return _leapProvider; }
66 set {
67 if (_leapProvider != null && Application.isPlaying) {
68 _leapProvider.OnFixedFrame -= onProviderFixedFrame;
69 }
70
71 _leapProvider = value;
72
73 if (_leapProvider != null && Application.isPlaying) {
74 _leapProvider.OnFixedFrame += onProviderFixedFrame;
75 }
76 }
77 }
78
79 private Func<Leap.Frame, Leap.Hand> _handAccessorFunc;
86 get { return _handAccessorFunc; }
87 set { _handAccessorFunc = value; }
88 }
89
93 private Hand _handData = new Hand();
94
100 private Hand _unwarpedHandData = new Hand();
101
105 private Hand _hand;
106
107
108
109 public Transform headTransform;
110 #endregion
111
112 #region Unity Events
113
114 protected override void Reset() {
115 base.Reset();
116
117 enabledPrimaryHoverFingertips = new bool[] { true, true, true, false, false };
118 }
119
120 protected override void Start() {
121 base.Start();
122
123 // Check manual configuration if data mode is custom.
124 if (handDataMode == HandDataMode.Custom) {
125 if (leapProvider == null) {
126 Debug.LogError("handDataMode is set to Custom, but no provider is set! "
127 + "Please add a custom script that will configure the correct "
128 + "LeapProvider for this InteractionHand before its Start() is "
129 + "called, or set the handDataMode to a value other than Custom.",
130 this);
131 return;
132 }
133 else if (handAccessorFunc == null) {
134 Debug.LogError("handDataMode is set to Custom, but no handAccessorFunc has "
135 + "been set! Please add a custom script that will configure the "
136 + "hand accessor function that will convert Leap frames into "
137 + "Leap hand data for this InteractionHand before its Start() "
138 + "is called, or set the handDataMode to a value other than "
139 + "Custom.", this);
140 return;
141 }
142 }
143 else { // Otherwise, configure automatically.
144 if (leapProvider == null) {
145 leapProvider = Hands.Provider;
146
147 if (leapProvider == null) {
148 Debug.LogError("No LeapServiceProvider was found in your scene! Please "
149 + "make sure you have a LeapServiceProvider if you intend to "
150 + "use Leap hands in your scene.", this);
151 return;
152 }
153 }
154
155 if (handAccessorFunc == null) {
156 if (handDataMode == HandDataMode.PlayerLeft) {
157 handAccessorFunc = (frame) => frame.Hands.Query()
158 .FirstOrDefault(hand => hand.IsLeft);
159 }
160 else {
161 handAccessorFunc = (frame) => frame.Hands.Query()
162 .FirstOrDefault(hand => hand.IsRight);
163 }
164 }
165 }
166
167 leapProvider.OnFixedFrame -= onProviderFixedFrame; // avoid double-subscribe
168 leapProvider.OnFixedFrame += onProviderFixedFrame;
169
170 // Set up hover point Transform for the palm.
171 Transform palmTransform = new GameObject("Palm Transform").transform;
172 palmTransform.parent = this.transform;
173 _backingHoverPointTransform = palmTransform;
174
175 // Set up primary hover point Transforms for the fingertips. We'll only use
176 // some of them, depending on user settings.
177 for (int i = 0; i < 5; i++) {
178 Transform fingertipTransform = new GameObject("Fingertip Transform").transform;
179 fingertipTransform.parent = this.transform;
180 _backingFingertipTransforms.Add(fingertipTransform);
181 _fingertipTransforms.Add(null);
182 }
183 }
184
185 private void OnDestroy() {
186 if (_leapProvider != null) {
187 _leapProvider.OnFixedFrame -= onProviderFixedFrame;
188 }
189 }
190
191 private void onProviderFixedFrame(Leap.Frame frame) {
192 _hand = handAccessorFunc(frame);
193
194 if (_hand != null) {
195 _handData.CopyFrom(_hand);
196 _unwarpedHandData.CopyFrom(_handData);
197
198 refreshPointDataFromHand();
199 _lastCustomHandWasLeft = _unwarpedHandData.IsLeft;
200 }
201
202 }
203
204 #endregion
205
206 #region General InteractionController Implementation
207
211 public override bool isTracked { get { return _hand != null; } }
212
216 public override bool isBeingMoved { get { return isTracked; } }
217
227 public Hand leapHand { get { return _unwarpedHandData; } }
228
229 private bool _lastCustomHandWasLeft = false;
233 public override bool isLeft {
234 get {
235 switch (handDataMode) {
236 case HandDataMode.PlayerLeft:
237 return true;
238 case HandDataMode.PlayerRight:
239 return false;
240 case HandDataMode.Custom: default:
241 return _lastCustomHandWasLeft;
242 }
243 }
244 }
245
249 public override Vector3 position {
250 get { return _handData.PalmPosition.ToVector3(); }
251 }
252
256 public override Quaternion rotation {
257 get { return _handData.Rotation.ToQuaternion(); }
258 }
259
263 public override Vector3 velocity {
264 get { return isTracked ? leapHand.PalmVelocity.ToVector3() : Vector3.zero; }
265 }
266
272 get { return ControllerType.Hand; }
273 }
274
279 public override InteractionHand intHand {
280 get { return this; }
281 }
282
283 protected override void onObjectUnregistered(IInteractionBehaviour intObj) {
285 }
286
287 protected override void fixedUpdateController() {
288 // Transform the hand ahead if the manager is in a moving reference frame.
290 Vector3 transformAheadPosition;
291 Quaternion transformAheadRotation;
292 manager.TransformAheadByFixedUpdate(_unwarpedHandData.PalmPosition.ToVector3(),
293 _unwarpedHandData.Rotation.ToQuaternion(),
294 out transformAheadPosition,
295 out transformAheadRotation);
296 _unwarpedHandData.SetTransform(transformAheadPosition, transformAheadRotation);
297 }
298 }
299
300 #endregion
301
302 #region Hovering Controller Implementation
303
304 private Transform _backingHoverPointTransform = null;
305 public override Vector3 hoverPoint {
306 get {
307 if (_backingHoverPointTransform == null) {
308 return leapHand.PalmPosition.ToVector3();
309 }
310 else {
311 return _backingHoverPointTransform.position;
312 }
313 }
314 }
315
316 private List<Transform> _backingFingertipTransforms = new List<Transform>();
317 private List<Transform> _fingertipTransforms = new List<Transform>();
318 protected override List<Transform> _primaryHoverPoints {
319 get {
320 return _fingertipTransforms;
321 }
322 }
323
324 private void refreshPointDataFromHand() {
325 refreshHoverPoint();
326 refreshPrimaryHoverPoints();
327 refreshGraspManipulatorPoints();
328 }
329
330 private void refreshHoverPoint() {
331 _backingHoverPointTransform.position = leapHand.PalmPosition.ToVector3();
332 _backingHoverPointTransform.rotation = leapHand.Rotation.ToQuaternion();
333 }
334
335 private void refreshPrimaryHoverPoints() {
336 for (int i = 0; i < enabledPrimaryHoverFingertips.Length; i++) {
338 _fingertipTransforms[i] = _backingFingertipTransforms[i];
339
340 Finger finger = leapHand.Fingers[i];
341 _fingertipTransforms[i].position = finger.TipPosition.ToVector3();
342 _fingertipTransforms[i].rotation = finger.bones[3].Rotation.ToQuaternion();
343 }
344 else {
345 _fingertipTransforms[i] = null;
346 }
347 }
348 }
349
350 protected override void unwarpColliders(Transform primaryHoverPoint,
351 ISpaceComponent warpedSpaceElement) {
352 // Extension method calculates "unwarped" pose in world space.
353 Vector3 unwarpedPosition;
354 Quaternion unwarpedRotation;
355 warpedSpaceElement.anchor.transformer.WorldSpaceUnwarp(primaryHoverPoint.position,
356 primaryHoverPoint.rotation,
357 out unwarpedPosition,
358 out unwarpedRotation);
359
360 // First shift the hand to be centered on the fingertip position so that rotations
361 // applied to the hand will pivot around the fingertip, then apply the rest of the
362 // transformation.
363 _unwarpedHandData.Transform(-primaryHoverPoint.position, Quaternion.identity);
364 _unwarpedHandData.Transform(unwarpedPosition, unwarpedRotation
365 * Quaternion.Inverse(primaryHoverPoint.rotation));
366
367 // Hand data was modified, so refresh point data.
368 refreshPointDataFromHand();
369 }
370
371 #endregion
372
373 #region Contact Controller Implementation
374
375 private const int NUM_FINGERS = 5;
376 private const int BONES_PER_FINGER = 3;
377
378 private ContactBone[] _contactBones;
379 public override ContactBone[] contactBones {
380 get { return _contactBones; }
381 }
382
383 private GameObject _contactBoneParent;
384 protected override GameObject contactBoneParent {
385 get { return _contactBoneParent; }
386 }
387
388 private delegate void BoneMapFunc(Leap.Hand hand, out Vector3 targetPosition,
389 out Quaternion targetRotation);
390 private BoneMapFunc[] _handContactBoneMapFunctions;
391
392 protected override void getColliderBoneTargetPositionRotation(int contactBoneIndex,
393 out Vector3 targetPosition,
394 out Quaternion targetRotation) {
395 using (new ProfilerSample("InteractionHand: getColliderBoneTargetPositionRotation")) {
396 _handContactBoneMapFunctions[contactBoneIndex](_unwarpedHandData,
397 out targetPosition,
398 out targetRotation);
399 }
400 }
401
402 protected override bool initContact() {
403 if (!isTracked) return false;
404
405 initContactBoneContainer();
406 initContactBones();
407
408 return true;
409 }
410
411 protected override void onPreEnableSoftContact() {
412 resetContactBoneJoints();
413 }
414
415 protected override void onPostDisableSoftContact() {
416 if (isTracked) resetContactBoneJoints();
417 }
418
419 #region Contact Bone Management
420
421 private void initContactBoneContainer() {
422 string name = (_unwarpedHandData.IsLeft ? "Left" : "Right") + " Interaction Hand Contact Bones";
423 _contactBoneParent = new GameObject(name);
424 }
425
426 private void initContactBones() {
427 _contactBones = new ContactBone[NUM_FINGERS * BONES_PER_FINGER + 1];
428 _handContactBoneMapFunctions = new BoneMapFunc[NUM_FINGERS * BONES_PER_FINGER + 1];
429
430 // Finger bones
431 for (int fingerIndex = 0; fingerIndex < NUM_FINGERS; fingerIndex++) {
432 for (int jointIndex = 0; jointIndex < BONES_PER_FINGER; jointIndex++) {
433 GameObject contactBoneObj = new GameObject("Contact Fingerbone", typeof(CapsuleCollider), typeof(Rigidbody), typeof(ContactBone));
434 contactBoneObj.layer = manager.contactBoneLayer;
435
436 Bone bone = _unwarpedHandData.Fingers[fingerIndex]
437 .Bone((Bone.BoneType)(jointIndex) + 1); // +1 to skip first bone.
438 int boneArrayIndex = fingerIndex * BONES_PER_FINGER + jointIndex;
439 contactBoneObj.transform.position = bone.Center.ToVector3();
440 contactBoneObj.transform.rotation = bone.Rotation.ToQuaternion();
441
442 // Remember the method we used to calculate this bone position from
443 // a Leap Hand for later.
444 int fingerIndexCopy = fingerIndex;
445 int jointIndexCopy = jointIndex;
446 _handContactBoneMapFunctions[boneArrayIndex] = (Leap.Hand hand,
447 out Vector3 targetPosition,
448 out Quaternion targetRotation) => {
449 Bone theBone = hand.Fingers[fingerIndexCopy].Bone((Bone.BoneType)(jointIndexCopy + 1));
450 targetPosition = theBone.Center.ToVector3();
451 targetRotation = theBone.Rotation.ToQuaternion();
452 };
453
454 CapsuleCollider capsule = contactBoneObj.GetComponent<CapsuleCollider>();
455 capsule.direction = 2;
456 capsule.radius = bone.Width * 0.5f;
457 capsule.height = bone.Length + bone.Width;
458 capsule.material = defaultContactBoneMaterial;
459
460 ContactBone contactBone = initContactBone(bone, contactBoneObj, boneArrayIndex, capsule);
461
462 contactBone.lastTargetPosition = bone.Center.ToVector3();
463 }
464 }
465
466 // Palm bone
467 {
468 // Palm is attached to the third metacarpal and derived from it.
469 GameObject contactBoneObj = new GameObject("Contact Palm Bone", typeof(BoxCollider), typeof(Rigidbody), typeof(ContactBone));
470
471 Bone bone = _unwarpedHandData.Fingers[(int)Finger.FingerType.TYPE_MIDDLE].Bone(Bone.BoneType.TYPE_METACARPAL);
472 int boneArrayIndex = NUM_FINGERS * BONES_PER_FINGER;
473 contactBoneObj.transform.position = _unwarpedHandData.PalmPosition.ToVector3();
474 contactBoneObj.transform.rotation = _unwarpedHandData.Rotation.ToQuaternion();
475
476 // Remember the method we used to calculate the palm from a Leap Hand for later.
477 _handContactBoneMapFunctions[boneArrayIndex] = (Leap.Hand hand,
478 out Vector3 targetPosition,
479 out Quaternion targetRotation) => {
480 targetPosition = hand.PalmPosition.ToVector3();
481 targetRotation = hand.Rotation.ToQuaternion();
482 };
483
484 BoxCollider box = contactBoneObj.GetComponent<BoxCollider>();
485 box.center = new Vector3(_unwarpedHandData.IsLeft ? -0.005f : 0.005f, bone.Width * -0.3f, -0.01f);
486 box.size = new Vector3(bone.Length, bone.Width, bone.Length);
487 box.material = defaultContactBoneMaterial;
488
489 initContactBone(null, contactBoneObj, boneArrayIndex, box);
490 }
491
492 // Constrain the bones to each other to prevent separation.
493 addContactBoneJoints();
494 }
495
496 private ContactBone initContactBone(Leap.Bone bone, GameObject contactBoneObj, int boneArrayIndex, Collider boneCollider) {
497 contactBoneObj.layer = _contactBoneParent.gameObject.layer;
498 contactBoneObj.transform.localScale = Vector3.one;
499
500 ContactBone contactBone = contactBoneObj.GetComponent<ContactBone>();
501 contactBone.collider = boneCollider;
502 contactBone.interactionController = this;
503 contactBone.interactionHand = this;
504 _contactBones[boneArrayIndex] = contactBone;
505
506 Transform capsuleTransform = contactBoneObj.transform;
507 capsuleTransform.SetParent(_contactBoneParent.transform, false);
508
509 Rigidbody body = contactBoneObj.GetComponent<Rigidbody>();
510 body.freezeRotation = true;
511 contactBone.rigidbody = body;
512 body.useGravity = false;
513 body.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic; // TODO: Allow different collision detection modes as an optimization.
514
515 body.mass = 0.1f;
516 body.position = bone != null ? bone.Center.ToVector3()
517 : _unwarpedHandData.PalmPosition.ToVector3();
518 body.rotation = bone != null ? bone.Rotation.ToQuaternion()
519 : _unwarpedHandData.Rotation.ToQuaternion();
520 contactBone.lastTargetPosition = bone != null ? bone.Center.ToVector3()
521 : _unwarpedHandData.PalmPosition.ToVector3();
522
523 return contactBone;
524 }
525
526 private void addContactBoneJoints() {
527 for (int fingerIndex = 0; fingerIndex < NUM_FINGERS; fingerIndex++) {
528 for (int jointIndex = 0; jointIndex < BONES_PER_FINGER; jointIndex++) {
529 Bone bone = _unwarpedHandData.Fingers[fingerIndex].Bone((Bone.BoneType)(jointIndex) + 1); // +1 to skip first bone.
530 int boneArrayIndex = fingerIndex * BONES_PER_FINGER + jointIndex;
531
532 FixedJoint joint = _contactBones[boneArrayIndex].gameObject.AddComponent<FixedJoint>();
533 joint.autoConfigureConnectedAnchor = false;
534 if (jointIndex != 0) {
535 Bone prevBone = _unwarpedHandData.Fingers[fingerIndex].Bone((Bone.BoneType)(jointIndex));
536 joint.connectedBody = _contactBones[boneArrayIndex - 1].rigidbody;
537 joint.anchor = Vector3.back * bone.Length / 2f;
538 joint.connectedAnchor = Vector3.forward * prevBone.Length / 2f;
539 _contactBones[boneArrayIndex].joint = joint;
540 }
541 else {
542 joint.connectedBody = _contactBones[NUM_FINGERS * BONES_PER_FINGER].rigidbody;
543 joint.anchor = Vector3.back * bone.Length / 2f;
544 joint.connectedAnchor = _contactBones[NUM_FINGERS * BONES_PER_FINGER].transform.InverseTransformPoint(bone.PrevJoint.ToVector3());
545 _contactBones[boneArrayIndex].metacarpalJoint = joint;
546 }
547 }
548 }
549 }
550
552 private void resetContactBoneJoints() {
553 // If contact bones array is null, there's nothing to reset. This can happen if
554 // the controller is disabled before it had a chance to initialize contact.
555 if (_contactBones == null) return;
556
557 // If the palm contact bone is null, we can't reset bone joints.
558 if (_contactBones[NUM_FINGERS * BONES_PER_FINGER] == null) return;
559
560 _contactBones[NUM_FINGERS * BONES_PER_FINGER].transform.position = _unwarpedHandData.PalmPosition.ToVector3();
561 _contactBones[NUM_FINGERS * BONES_PER_FINGER].transform.rotation = _unwarpedHandData.Rotation.ToQuaternion();
562 _contactBones[NUM_FINGERS * BONES_PER_FINGER].rigidbody.velocity = Vector3.zero;
563 _contactBones[NUM_FINGERS * BONES_PER_FINGER].rigidbody.angularVelocity = Vector3.zero;
564
565 for (int fingerIndex = 0; fingerIndex < NUM_FINGERS; fingerIndex++) {
566 for (int jointIndex = 0; jointIndex < BONES_PER_FINGER; jointIndex++) {
567 Bone bone = _unwarpedHandData.Fingers[fingerIndex].Bone((Bone.BoneType)(jointIndex) + 1); // +1 to skip first bone.
568 int boneArrayIndex = fingerIndex * BONES_PER_FINGER + jointIndex;
569
570 _contactBones[boneArrayIndex].transform.position = bone.Center.ToVector3();
571 _contactBones[boneArrayIndex].transform.rotation = bone.Rotation.ToQuaternion();
572 _contactBones[boneArrayIndex].rigidbody.position = bone.Center.ToVector3();
573 _contactBones[boneArrayIndex].rigidbody.rotation = bone.Rotation.ToQuaternion();
574 _contactBones[boneArrayIndex].rigidbody.velocity = Vector3.zero;
575 _contactBones[boneArrayIndex].rigidbody.angularVelocity = Vector3.zero;
576
577 if (jointIndex != 0 && _contactBones[boneArrayIndex].joint != null) {
578 Bone prevBone = _unwarpedHandData.Fingers[fingerIndex].Bone((Bone.BoneType)(jointIndex));
579 _contactBones[boneArrayIndex].joint.connectedBody = _contactBones[boneArrayIndex - 1].rigidbody;
580 _contactBones[boneArrayIndex].joint.anchor = Vector3.back * bone.Length / 2f;
581 _contactBones[boneArrayIndex].joint.connectedAnchor = Vector3.forward * prevBone.Length / 2f;
582 }
583 else if (_contactBones[boneArrayIndex].metacarpalJoint != null) {
584 _contactBones[boneArrayIndex].metacarpalJoint.connectedBody = _contactBones[NUM_FINGERS * BONES_PER_FINGER].rigidbody;
585 _contactBones[boneArrayIndex].metacarpalJoint.anchor = Vector3.back * bone.Length / 2f;
586 _contactBones[boneArrayIndex].metacarpalJoint.connectedAnchor = _contactBones[NUM_FINGERS * BONES_PER_FINGER].transform
587 .InverseTransformPoint(bone.PrevJoint.ToVector3());
588 }
589 }
590 }
591 }
592
597 public void FillBones(Hand inHand) {
598 if (softContactEnabled) { return; }
599 if (Application.isPlaying && _contactBones.Length == NUM_FINGERS * BONES_PER_FINGER + 1) {
600 Vector elbowPos = inHand.Arm.ElbowPosition;
601 inHand.SetTransform(_contactBones[NUM_FINGERS * BONES_PER_FINGER].rigidbody.position, _contactBones[NUM_FINGERS * BONES_PER_FINGER].rigidbody.rotation);
602
603 for (int fingerIndex = 0; fingerIndex < NUM_FINGERS; fingerIndex++) {
604 for (int jointIndex = 0; jointIndex < BONES_PER_FINGER; jointIndex++) {
605 Bone bone = inHand.Fingers[fingerIndex].Bone((Bone.BoneType)(jointIndex) + 1);
606 int boneArrayIndex = fingerIndex * BONES_PER_FINGER + jointIndex;
607 Vector displacement = _contactBones[boneArrayIndex].rigidbody.position.ToVector() - bone.Center;
608 bone.Center += displacement;
609 bone.PrevJoint += displacement;
610 bone.NextJoint += displacement;
611 bone.Rotation = _contactBones[boneArrayIndex].rigidbody.rotation.ToLeapQuaternion();
612 }
613 }
614
615 inHand.Arm.PrevJoint = elbowPos;
616 inHand.Arm.Direction = (inHand.Arm.PrevJoint - inHand.Arm.NextJoint).Normalized;
617 inHand.Arm.Center = (inHand.Arm.PrevJoint + inHand.Arm.NextJoint) * 0.5f;
618 }
619 }
620
621 #endregion
622
623 #endregion
624
625 #region Grasp Controller Implementation
626
627 private List<Vector3> _graspManipulatorPoints = new List<Vector3>();
628 public override List<Vector3> graspManipulatorPoints {
629 get {
630 return _graspManipulatorPoints;
631 }
632 }
633
634 private void refreshGraspManipulatorPoints() {
635 int bufferIndex = 0;
636 for (int i = 0; i < NUM_FINGERS; i++) {
637 for (int boneIdx = 0; boneIdx < 2; boneIdx++) {
638 // Update or add knuckle-joint and first-finger-bone positions as the grasp
639 // manipulator points for this Hand.
640
641 Vector3 point = leapHand.Fingers[i].bones[boneIdx].NextJoint.ToVector3();
642
643 if (_graspManipulatorPoints.Count - 1 < bufferIndex) {
644 _graspManipulatorPoints.Add(point);
645 }
646 else {
647 _graspManipulatorPoints[bufferIndex] = point;
648 }
649 bufferIndex += 1;
650 }
651 }
652 }
653
654 private HeuristicGrabClassifier _grabClassifier;
659 get {
660 if (_grabClassifier == null) _grabClassifier = new HeuristicGrabClassifier(this);
661 return _grabClassifier;
662 }
663 }
664
665 private Vector3[] _fingertipPositionsBuffer = new Vector3[5];
673 public override Vector3 GetGraspPoint() {
674 if (!isGraspingObject) {
675 Debug.LogError("Tried to get grasp point of InteractionHand, but it is not "
676 + "currently grasping an object.", this);
677 return leapHand.PalmPosition.ToVector3();
678 }
679
680 int numGraspingFingertips = 0;
681 _grabClassifier.GetGraspingFingertipPositions(graspedObject, _fingertipPositionsBuffer, out numGraspingFingertips);
682 if (numGraspingFingertips > 0) {
683 Vector3 sum = Vector3.zero;
684 for (int i = 0; i < numGraspingFingertips; i++) {
685 sum += _fingertipPositionsBuffer[i];
686 }
687 return sum / numGraspingFingertips;
688 }
689 else {
690 return leapHand.PalmPosition.ToVector3();
691 }
692 }
693
700 protected override bool checkShouldGraspAtemporal(IInteractionBehaviour intObj) {
701 if (grabClassifier.TryGrasp(intObj, leapHand)) {
702 var tempControllers = Pool<List<InteractionController>>.Spawn();
703 try {
704 tempControllers.Add(this);
705 intObj.BeginGrasp(tempControllers);
706 return true;
707 }
708 finally {
709 tempControllers.Clear();
710 Pool<List<InteractionController>>.Recycle(tempControllers);
711 }
712 }
713
714 return false;
715 }
716
717 public override void SwapGrasp(IInteractionBehaviour replacement) {
718 var original = graspedObject;
719
720 base.SwapGrasp(replacement);
721
722 grabClassifier.SwapClassifierState(original, replacement);
723 }
724
725 protected override void fixedUpdateGraspingState() {
726 //Feed Camera Transform in for Projective Grabbing Hack (details inside)
728 }
729
730 protected override void onGraspedObjectForciblyReleased(IInteractionBehaviour objectToBeReleased) {
732 }
733
734 protected override bool checkShouldRelease(out IInteractionBehaviour objectToRelease) {
735 return grabClassifier.FixedUpdateClassifierRelease(out objectToRelease);
736 }
737
738 protected override bool checkShouldGrasp(out IInteractionBehaviour objectToGrasp) {
739 return grabClassifier.FixedUpdateClassifierGrasp(out objectToGrasp);
740 }
741
742 #endregion
743
744 #region Gizmos
745
746 #if UNITY_EDITOR
747
748 private Leap.Hand _testHand = null;
749
750 public override void OnDrawRuntimeGizmos(RuntimeGizmoDrawer drawer) {
751 if (Application.isPlaying) {
752 base.OnDrawRuntimeGizmos(drawer);
753 }
754 else {
755 var provider = leapProvider;
756 if (provider == null) {
757 provider = Hands.Provider;
758 }
759
760 if (_testHand == null && provider != null) {
761 _testHand = provider.MakeTestHand(this.isLeft);
762 }
763
764 // Hover Point
765 _unwarpedHandData = _testHand; // hoverPoint is driven by this backing variable
766 drawHoverPoint(drawer, hoverPoint);
767
768 // Primary Hover Points
769 for (int i = 0; i < NUM_FINGERS; i++) {
771 drawPrimaryHoverPoint(drawer, _testHand.Fingers[i].TipPosition.ToVector3());
772 }
773 }
774 }
775 }
776
777 #endif
778
779 #endregion
780
781 }
782
783}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
Vector ElbowPosition
The position of the elbow. If not in view, the elbow position is estimated based on typical human ana...
Definition: Arm.cs:71
The Bone class represents a tracked bone.
Definition: Bone.cs:26
LeapQuaternion Rotation
The orientation of this Bone as a Quaternion.
Definition: Bone.cs:126
Vector Direction
The normalized direction of the bone from base to tip.
Definition: Bone.cs:102
float Width
The average width of the flesh around the bone.
Definition: Bone.cs:114
BoneType
Enumerates the type of bones.
Definition: Bone.cs:168
Vector Center
The midpoint of the bone.
Definition: Bone.cs:96
Vector PrevJoint
The base of the bone, closest to the wrist. In anatomical terms, this is the proximal end of the bone...
Definition: Bone.cs:83
Bone()
Constructs a default invalid Bone object.
Definition: Bone.cs:33
float Length
The estimated length of the bone.
Definition: Bone.cs:108
Vector NextJoint
The end of the bone, closest to the finger tip. In anatomical terms, this is the distal end of the bo...
Definition: Bone.cs:90
The Finger class represents a tracked finger.
Definition: Finger.cs:20
Bone[] bones
Definition: Finger.cs:21
Vector TipPosition
The tip position of this Finger.
Definition: Finger.cs:122
The Frame class represents a set of hand and finger tracking data detected in a single frame.
Definition: Frame.cs:24
The Hand class reports the physical characteristics of a detected hand.
Definition: Hand.cs:26
Vector PalmVelocity
The rate of change of the palm position.
Definition: Hand.cs:171
bool IsLeft
Identifies whether this Hand is a left hand.
Definition: Hand.cs:296
Arm Arm
The arm to which this hand is attached.
Definition: Hand.cs:311
Vector PalmPosition
The center position of the palm.
Definition: Hand.cs:165
List< Finger > Fingers
The list of Finger objects detected in this frame that are attached to this hand, given in order from...
Definition: Hand.cs:159
LeapQuaternion Rotation
The rotation of the hand as a quaternion.
Definition: Hand.cs:211
Contact Bones store data for the colliders and rigidbodies in each bone of the contact-related repres...
Definition: ContactBone.cs:24
FixedJoint joint
InteractionHands use ContactBones to store additional, hand-specific data. Other InteractionControlle...
Definition: ContactBone.cs:93
FixedJoint metacarpalJoint
InteractionHands use ContactBones to store additional, hand-specific data. Other InteractionControlle...
Definition: ContactBone.cs:99
Rigidbody rigidbody
The Rigidbody of this ContactBone. This field must not be null for the ContactBone to work correctly.
Definition: ContactBone.cs:40
static void drawHoverPoint(RuntimeGizmoDrawer drawer, Vector3 pos)
static void drawPrimaryHoverPoint(RuntimeGizmoDrawer drawer, Vector3 pos)
virtual void OnDrawRuntimeGizmos(RuntimeGizmoDrawer drawer)
By default, this method will draw all of the colliders found in the contactBoneParent hierarchy,...
IInteractionBehaviour graspedObject
Gets the object the controller is currently grasping, or null if there is no such object.
bool isGraspingObject
Gets whether the controller is currently grasping an object.
override bool initContact()
Called to initialize contact colliders. See remarks for implementation requirements.
Func< Leap.Frame, Leap.Hand > handAccessorFunc
If the hand data mode for this InteractionHand is set to Custom, you must manually specify how this I...
bool[] enabledPrimaryHoverFingertips
Set slots to true to consider the corresponding finger's fingertip for primary hover checks....
override InteractionHand intHand
Returns this InteractionHand object. This property will be null if the InteractionControllerBase is n...
override void SwapGrasp(IInteractionBehaviour replacement)
Seamlessly swap the currently grasped object for a replacement object. It will behave like the hand r...
override void onGraspedObjectForciblyReleased(IInteractionBehaviour objectToBeReleased)
Optionally override this method to perform logic just before a grasped object is released because it ...
override void unwarpColliders(Transform primaryHoverPoint, ISpaceComponent warpedSpaceElement)
Implementing this method is necessary to support curved spaces as rendered by a Leap Graphic Renderer...
override bool checkShouldGraspAtemporal(IInteractionBehaviour intObj)
Attempts to manually initiate a grasp on the argument interaction object. A grasp will only begin if ...
override List< Vector3 > graspManipulatorPoints
void FillBones(Hand inHand)
A utility function that sets a Hand object's bones based on this InteractionHand. Can be used to disp...
override bool isTracked
Gets whether the underlying Leap hand is currently tracked.
override bool isLeft
Gets whether the underlying tracked Leap hand is a left hand.
Hand leapHand
Gets the last tracked state of the Leap hand.
override Vector3 position
Gets the last-tracked position of the underlying Leap hand.
override void onPreEnableSoftContact()
Optionally override this method to perform logic just before soft contact is enabled for this control...
override List< Transform > _primaryHoverPoints
override void getColliderBoneTargetPositionRotation(int contactBoneIndex, out Vector3 targetPosition, out Quaternion targetRotation)
If your controller features no moving colliders relative to itself, simply return the desired positio...
override void fixedUpdateGraspingState()
Called every fixed frame if grasping is enabled in the Interaction Manager.
override Vector3 velocity
Gets the velocity of the underlying tracked Leap hand.
override bool checkShouldRelease(out IInteractionBehaviour objectToRelease)
Returns whether this controller should release an object this fixed frame, and if so,...
override void onPostDisableSoftContact()
Optionally override this method to perform logic just after soft contact is disabled for this control...
override bool isBeingMoved
Gets whether the underlying Leap hand is currently being moved in worldspace.
override Vector3 GetGraspPoint()
Returns approximately where the controller is grasping the currently-grasped InteractionBehaviour....
override void fixedUpdateController()
Called just before the InteractionController proceeds with its usual FixedUpdate.
override bool checkShouldGrasp(out IInteractionBehaviour objectToGrasp)
Returns whether this controller should grasp an object this fixed frame, and if so,...
HeuristicGrabClassifier grabClassifier
Handles logic determining whether a hand has grabbed or released an interaction object.
override Quaternion rotation
Gets the last-tracked rotation of the underlying Leap hand.
override ControllerType controllerType
Gets the controller type of this InteractionControllerBase. InteractionHands are Interaction Engine c...
LeapProvider leapProvider
If the hand data mode for this InteractionHand is set to Custom, you must also manually specify the p...
override void onObjectUnregistered(IInteractionBehaviour intObj)
This method is called by the InteractionController when it is notified by the InteractionManager that...
void TransformAheadByFixedUpdate(Vector3 position, Quaternion rotation, out Vector3 newPosition, out Quaternion newRotation)
Transforms a position and rotation ahead by one FixedUpdate based on the prior motion of the Interact...
bool TryGrasp(IInteractionBehaviour intObj, Hand hand)
bool FixedUpdateClassifierRelease(out IInteractionBehaviour releasedObject)
void FixedUpdateClassifierHandState(Transform headTransform=null)
void UnregisterInteractionBehaviour(IInteractionBehaviour behaviour)
void SwapClassifierState(IInteractionBehaviour original, IInteractionBehaviour replacement)
void GetGraspingFingertipPositions(IInteractionBehaviour behaviour, Vector3[] fingertipPositionsBuffer, out int numGraspingFingertips)
void NotifyGraspForciblyReleased(IInteractionBehaviour behaviour)
bool FixedUpdateClassifierGrasp(out IInteractionBehaviour graspedObject)
Provides Frame object data to the Unity application by firing events as soon as Frame data is availab...
Definition: LeapProvider.cs:21
Action< Frame > OnFixedFrame
Definition: LeapProvider.cs:26
IInteractionBehaviour is the interface that defines all Interaction objects, specifying the minimum s...
void BeginGrasp(List< InteractionController > beganGrasping)
ControllerType
The Interaction Engine can be controlled by hands tracked by the Leap Motion Controller,...
A utility struct for ease of use when you want to wrap a piece of code in a Profiler....
The Vector struct represents a three-component mathematical vector or point such as a direction or po...
Definition: Vector.cs:36