338 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			338 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| /************************************************************************************
 | |
| Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
 | |
| 
 | |
| Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at
 | |
| https://developer.oculus.com/licenses/oculussdk/
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, the Utilities SDK distributed
 | |
| under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
 | |
| ANY KIND, either express or implied. See the License for the specific language governing
 | |
| permissions and limitations under the License.
 | |
| ************************************************************************************/
 | |
| 
 | |
| using Oculus.Interaction.Input;
 | |
| using UnityEngine;
 | |
| using UnityEngine.Assertions;
 | |
| 
 | |
| namespace Oculus.Interaction.GrabAPI
 | |
| {
 | |
|     public class HandGrabAPI : MonoBehaviour
 | |
|     {
 | |
|         [SerializeField, Interface(typeof(IHand))]
 | |
|         private MonoBehaviour _hand;
 | |
| 
 | |
|         public IHand Hand { get; private set; }
 | |
| 
 | |
|         private IFingerAPI _fingerPinchAPI = new FingerPinchAPI();
 | |
|         private IFingerAPI _fingerPalmAPI = new FingerGrabAPI();
 | |
| 
 | |
|         private bool _started;
 | |
| 
 | |
|         protected virtual void Awake()
 | |
|         {
 | |
|             Hand = _hand as IHand;
 | |
|         }
 | |
| 
 | |
|         protected virtual void Start()
 | |
|         {
 | |
|             this.BeginStart(ref _started);
 | |
|             Assert.IsNotNull(Hand);
 | |
|             Assert.IsNotNull(_fingerPinchAPI);
 | |
|             Assert.IsNotNull(_fingerPalmAPI);
 | |
|             this.EndStart(ref _started);
 | |
|         }
 | |
| 
 | |
|         protected virtual void Update()
 | |
|         {
 | |
|             _fingerPinchAPI.Update(Hand);
 | |
|             _fingerPalmAPI.Update(Hand);
 | |
|         }
 | |
| 
 | |
|         public HandFingerFlags HandPinchingFinger()
 | |
|         {
 | |
|             return HandGrabbingFingers(_fingerPinchAPI);
 | |
|         }
 | |
| 
 | |
|         public HandFingerFlags HandPalmGrabbingFingers()
 | |
|         {
 | |
|             return HandGrabbingFingers(_fingerPalmAPI);
 | |
|         }
 | |
| 
 | |
|         private HandFingerFlags HandGrabbingFingers(IFingerAPI fingerAPI)
 | |
|         {
 | |
|             HandFingerFlags grabbingFingers = HandFingerFlags.None;
 | |
| 
 | |
|             for (int i = 0; i < Constants.NUM_FINGERS; i++)
 | |
|             {
 | |
|                 HandFinger finger = (HandFinger)i;
 | |
| 
 | |
|                 bool isGrabbing = fingerAPI.GetFingerIsGrabbing(finger);
 | |
|                 if (isGrabbing)
 | |
|                 {
 | |
|                     grabbingFingers |= (HandFingerFlags)(1 << i);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return grabbingFingers;
 | |
|         }
 | |
| 
 | |
|         public bool IsHandPinchGrabbing(in GrabbingRule fingers)
 | |
|         {
 | |
|             HandFingerFlags pinchFingers = HandPinchingFinger();
 | |
|             return IsSustainingGrab(fingers, pinchFingers);
 | |
|         }
 | |
| 
 | |
|         public bool IsHandPalmGrabbing(in GrabbingRule fingers)
 | |
|         {
 | |
|             HandFingerFlags palmFingers = HandPalmGrabbingFingers();
 | |
|             return IsSustainingGrab(fingers, palmFingers);
 | |
|         }
 | |
| 
 | |
|         public bool IsSustainingGrab(in GrabbingRule fingers, HandFingerFlags grabbingFingers)
 | |
|         {
 | |
|             for (int i = 0; i < Constants.NUM_FINGERS; i++)
 | |
|             {
 | |
|                 HandFinger finger = (HandFinger)i;
 | |
|                 HandFingerFlags fingerFlag = (HandFingerFlags)(1 << i);
 | |
| 
 | |
|                 bool isFingerGrabbing = (grabbingFingers & fingerFlag) != 0;
 | |
|                 if (fingers[finger] == FingerRequirement.Required)
 | |
|                 {
 | |
|                     if (fingers.UnselectMode == FingerUnselectMode.AnyReleased
 | |
|                         && !isFingerGrabbing)
 | |
|                     {
 | |
|                         return false;
 | |
|                     }
 | |
| 
 | |
|                     if(fingers.UnselectMode == FingerUnselectMode.AllReleased
 | |
|                         && isFingerGrabbing)
 | |
|                     {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|                 else if (fingers[finger] == FingerRequirement.Optional)
 | |
|                 {
 | |
|                     if (fingers.UnselectMode == FingerUnselectMode.AnyReleased
 | |
|                         && !isFingerGrabbing)
 | |
|                     {
 | |
|                         return false;
 | |
|                     }
 | |
| 
 | |
|                     if (fingers.UnselectMode == FingerUnselectMode.AllReleased
 | |
|                         && isFingerGrabbing)
 | |
|                     {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Determine whether the state of any of the finger pinches have changed this frame to
 | |
|         /// the target pinching state (on/off).
 | |
|         /// </summary>
 | |
|         /// <param name="fingers">Finger rules to check.</param>
 | |
|         public bool IsHandSelectPinchFingersChanged(in GrabbingRule fingers)
 | |
|         {
 | |
|             return IsHandSelectFingersChanged(fingers, _fingerPinchAPI);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Determine whether the state of any of the finger grabs have changed this frame to
 | |
|         /// the target grabbing state (on/off).
 | |
|         /// </summary>
 | |
|         /// <param name="fingers">Finger rules to check.</param>
 | |
|         public bool IsHandSelectPalmFingersChanged(in GrabbingRule fingers)
 | |
|         {
 | |
|             return IsHandSelectFingersChanged(fingers, _fingerPalmAPI);
 | |
|         }
 | |
| 
 | |
|         public bool IsHandUnselectPinchFingersChanged(in GrabbingRule fingers)
 | |
|         {
 | |
|             return IsHandUnselectFingersChanged(fingers, _fingerPinchAPI);
 | |
|         }
 | |
| 
 | |
|         public bool IsHandUnselectPalmFingersChanged(in GrabbingRule fingers)
 | |
|         {
 | |
|             return IsHandUnselectFingersChanged(fingers, _fingerPalmAPI);
 | |
|         }
 | |
| 
 | |
|         private bool IsHandSelectFingersChanged(in GrabbingRule fingers, IFingerAPI fingerAPI)
 | |
|         {
 | |
|             bool selectsWithOptionals = fingers.SelectsWithOptionals;
 | |
|             bool aFingerGrabbed = false;
 | |
| 
 | |
|             for (int i = 0; i < Constants.NUM_FINGERS; i++)
 | |
|             {
 | |
|                 HandFinger finger = (HandFinger)i;
 | |
|                 if (fingers[finger] == FingerRequirement.Required)
 | |
|                 {
 | |
|                     if (!fingerAPI.GetFingerIsGrabbing(finger))
 | |
|                     {
 | |
|                         return false;
 | |
|                     }
 | |
| 
 | |
|                     if (fingerAPI.GetFingerIsGrabbingChanged(finger, true))
 | |
|                     {
 | |
|                         aFingerGrabbed = true;
 | |
|                     }
 | |
|                 }
 | |
|                 else if (selectsWithOptionals
 | |
|                     && fingers[finger] == FingerRequirement.Optional)
 | |
|                 {
 | |
|                     if (fingerAPI.GetFingerIsGrabbingChanged(finger, true))
 | |
|                     {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return aFingerGrabbed;
 | |
|         }
 | |
| 
 | |
|         private bool IsHandUnselectFingersChanged(in GrabbingRule fingers, IFingerAPI fingerAPI)
 | |
|         {
 | |
|             bool isAnyFingerGrabbing = false;
 | |
|             bool aFingerUngrabbed = false;
 | |
|             bool selectsWithOptionals = fingers.SelectsWithOptionals;
 | |
|             for (int i = 0; i < Constants.NUM_FINGERS; i++)
 | |
|             {
 | |
|                 HandFinger finger = (HandFinger)i;
 | |
|                 if (fingers[finger] == FingerRequirement.Ignored)
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 isAnyFingerGrabbing |= fingerAPI.GetFingerIsGrabbing(finger);
 | |
|                 if (fingers[finger] == FingerRequirement.Required)
 | |
|                 {
 | |
|                     if (fingerAPI.GetFingerIsGrabbingChanged(finger, false))
 | |
|                     {
 | |
|                         aFingerUngrabbed = true;
 | |
|                         if (fingers.UnselectMode == FingerUnselectMode.AnyReleased)
 | |
|                         {
 | |
|                             return true;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (fingers[finger] == FingerRequirement.Optional)
 | |
|                 {
 | |
|                     if (fingerAPI.GetFingerIsGrabbingChanged(finger, false))
 | |
|                     {
 | |
|                         aFingerUngrabbed = true;
 | |
|                         if (fingers.UnselectMode == FingerUnselectMode.AnyReleased
 | |
|                             && selectsWithOptionals)
 | |
|                         {
 | |
|                             return true;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return !isAnyFingerGrabbing && aFingerUngrabbed;
 | |
|         }
 | |
| 
 | |
|         public Vector3 GetPinchCenter()
 | |
|         {
 | |
|             return WristOffsetToWorldPoint(_fingerPinchAPI.GetCenterOffset());
 | |
|         }
 | |
| 
 | |
|         public Vector3 GetPalmCenter()
 | |
|         {
 | |
|             return WristOffsetToWorldPoint(_fingerPalmAPI.GetCenterOffset());
 | |
|         }
 | |
| 
 | |
|         private Vector3 WristOffsetToWorldPoint(Vector3 offset)
 | |
|         {
 | |
|             if (!Hand.GetJointPose(HandJointId.HandWristRoot, out Pose wristPose))
 | |
|             {
 | |
|                 return offset;
 | |
|             }
 | |
| 
 | |
|             return wristPose.position + wristPose.rotation * offset;
 | |
|         }
 | |
| 
 | |
|         public float GetHandPinchStrength(in GrabbingRule fingers,
 | |
|             bool includePinching = true)
 | |
|         {
 | |
|             return GetHandStrength(fingers, includePinching, _fingerPinchAPI);
 | |
|         }
 | |
| 
 | |
|         public float GetHandPalmStrength(in GrabbingRule fingers,
 | |
|             bool includeGrabbing = true)
 | |
|         {
 | |
|             return GetHandStrength(fingers, includeGrabbing, _fingerPalmAPI);
 | |
|         }
 | |
| 
 | |
|         public float GetFingerPinchStrength(HandFinger finger)
 | |
|         {
 | |
|             return _fingerPinchAPI.GetFingerGrabStrength(finger);
 | |
|         }
 | |
| 
 | |
|         public float GetFingerPalmStrength(HandFinger finger)
 | |
|         {
 | |
|             return _fingerPalmAPI.GetFingerGrabStrength(finger);
 | |
|         }
 | |
| 
 | |
|         private float GetHandStrength(in GrabbingRule fingers,
 | |
|             bool includeGrabbing, IFingerAPI fingerAPI)
 | |
|         {
 | |
|             float requiredMin = 1.0f;
 | |
|             float optionalMax = 0f;
 | |
|             for (int i = 0; i < Constants.NUM_FINGERS; i++)
 | |
|             {
 | |
|                 HandFinger finger = (HandFinger)i;
 | |
|                 if (!includeGrabbing && fingerAPI.GetFingerIsGrabbing((HandFinger)i))
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 if (fingers[finger] == FingerRequirement.Ignored)
 | |
|                 {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 if (fingers[finger] == FingerRequirement.Optional)
 | |
|                 {
 | |
|                     optionalMax = Mathf.Max(optionalMax, fingerAPI.GetFingerGrabStrength((HandFinger)i));
 | |
|                 }
 | |
| 
 | |
|                 if (fingers[finger] == FingerRequirement.Required)
 | |
|                 {
 | |
|                     requiredMin = Mathf.Min(requiredMin, fingerAPI.GetFingerGrabStrength((HandFinger)i));
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|             return Mathf.Min(requiredMin, optionalMax);
 | |
|         }
 | |
| 
 | |
|         #region Inject
 | |
| 
 | |
|         public void InjectAllHandGrabAPI(IHand hand)
 | |
|         {
 | |
|             InjectHand(hand);
 | |
|         }
 | |
| 
 | |
|         public void InjectHand(IHand hand)
 | |
|         {
 | |
|             _hand = hand as MonoBehaviour;
 | |
|             Hand = hand;
 | |
|         }
 | |
| 
 | |
|         public void InjectOptionalFingerPinchAPI(IFingerAPI fingerPinchAPI)
 | |
|         {
 | |
|             _fingerPinchAPI = fingerPinchAPI;
 | |
|         }
 | |
| 
 | |
|         public void InjectOptionalFingerGrabAPI(IFingerAPI fingerGrabAPI)
 | |
|         {
 | |
|             _fingerPalmAPI = fingerGrabAPI;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
|     }
 | |
| }
 |