summaryrefslogtreecommitdiff
path: root/Assets/Samples/XR Interaction Toolkit/3.1.2/Hands Interaction Demo/Scripts/PokeGestureDetector.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Assets/Samples/XR Interaction Toolkit/3.1.2/Hands Interaction Demo/Scripts/PokeGestureDetector.cs')
-rw-r--r--Assets/Samples/XR Interaction Toolkit/3.1.2/Hands Interaction Demo/Scripts/PokeGestureDetector.cs200
1 files changed, 200 insertions, 0 deletions
diff --git a/Assets/Samples/XR Interaction Toolkit/3.1.2/Hands Interaction Demo/Scripts/PokeGestureDetector.cs b/Assets/Samples/XR Interaction Toolkit/3.1.2/Hands Interaction Demo/Scripts/PokeGestureDetector.cs
new file mode 100644
index 0000000..85bfa1b
--- /dev/null
+++ b/Assets/Samples/XR Interaction Toolkit/3.1.2/Hands Interaction Demo/Scripts/PokeGestureDetector.cs
@@ -0,0 +1,200 @@
+using System.Collections.Generic;
+using UnityEngine.Events;
+#if XR_HANDS_1_1_OR_NEWER
+using UnityEngine.XR.Hands;
+#endif
+
+namespace UnityEngine.XR.Interaction.Toolkit.Samples.Hands
+{
+ /// <summary>
+ /// Behavior that provides events for when an <see cref="XRHand"/> starts and ends a poke gesture. The gesture is
+ /// detected if the index finger is extended and the middle, ring, and little fingers are curled in.
+ /// </summary>
+ public class PokeGestureDetector : MonoBehaviour
+ {
+ [SerializeField]
+ [Tooltip("Which hand to check for the poke gesture.")]
+#if XR_HANDS_1_1_OR_NEWER
+ Handedness m_Handedness;
+#else
+ int m_Handedness;
+#endif
+
+ [SerializeField]
+ [Tooltip("Called when the hand has started a poke gesture.")]
+ UnityEvent m_PokeGestureStarted;
+
+ [SerializeField]
+ [Tooltip("Called when the hand has ended a poke gesture.")]
+ UnityEvent m_PokeGestureEnded;
+
+#if XR_HANDS_1_1_OR_NEWER
+ XRHandSubsystem m_Subsystem;
+ bool m_IsPoking;
+
+ static readonly List<XRHandSubsystem> s_Subsystems = new List<XRHandSubsystem>();
+#endif
+
+ /// <summary>
+ /// See <see cref="MonoBehaviour"/>.
+ /// </summary>
+ protected void OnEnable()
+ {
+#if XR_HANDS_1_1_OR_NEWER
+ SubsystemManager.GetSubsystems(s_Subsystems);
+ if (s_Subsystems.Count == 0)
+ return;
+
+ m_Subsystem = s_Subsystems[0];
+ m_Subsystem.updatedHands += OnUpdatedHands;
+#else
+ Debug.LogError("Script requires XR Hands (com.unity.xr.hands) package. Install using Window > Package Manager or click Fix on the related issue in Edit > Project Settings > XR Plug-in Management > Project Validation.", this);
+#endif
+ }
+
+ /// <summary>
+ /// See <see cref="MonoBehaviour"/>.
+ /// </summary>
+ protected void OnDisable()
+ {
+#if XR_HANDS_1_1_OR_NEWER
+ if (m_Subsystem == null)
+ return;
+
+ m_Subsystem.updatedHands -= OnUpdatedHands;
+ m_Subsystem = null;
+#endif
+ }
+
+#if XR_HANDS_1_1_OR_NEWER
+ void OnUpdatedHands(XRHandSubsystem subsystem, XRHandSubsystem.UpdateSuccessFlags updateSuccessFlags, XRHandSubsystem.UpdateType updateType)
+ {
+ var wasPoking = m_IsPoking;
+ switch (m_Handedness)
+ {
+ case Handedness.Left:
+ if (!HasUpdateSuccessFlag(updateSuccessFlags, XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints))
+ return;
+
+ var leftHand = subsystem.leftHand;
+ m_IsPoking = IsIndexExtended(leftHand) && IsMiddleGrabbing(leftHand) && IsRingGrabbing(leftHand) &&
+ IsLittleGrabbing(leftHand);
+ break;
+ case Handedness.Right:
+ if (!HasUpdateSuccessFlag(updateSuccessFlags, XRHandSubsystem.UpdateSuccessFlags.RightHandJoints))
+ return;
+
+ var rightHand = subsystem.rightHand;
+ m_IsPoking = IsIndexExtended(rightHand) && IsMiddleGrabbing(rightHand) && IsRingGrabbing(rightHand) &&
+ IsLittleGrabbing(rightHand);
+ break;
+ }
+
+ if (m_IsPoking && !wasPoking)
+ StartPokeGesture();
+ else if (!m_IsPoking && wasPoking)
+ EndPokeGesture();
+ }
+
+ /// <summary>
+ /// Determines whether one or more bit fields are set in the flags.
+ /// Non-boxing version of <c>HasFlag</c> for <see cref="XRHandSubsystem.UpdateSuccessFlags"/>.
+ /// </summary>
+ /// <param name="successFlags">The flags enum instance.</param>
+ /// <param name="successFlag">The flag to check if set.</param>
+ /// <returns>Returns <see langword="true"/> if the bit field or bit fields are set, otherwise returns <see langword="false"/>.</returns>
+ static bool HasUpdateSuccessFlag(XRHandSubsystem.UpdateSuccessFlags successFlags, XRHandSubsystem.UpdateSuccessFlags successFlag)
+ {
+ return (successFlags & successFlag) == successFlag;
+ }
+
+ /// <summary>
+ /// Returns true if the given hand's index finger tip is farther from the wrist than the index intermediate joint.
+ /// </summary>
+ /// <param name="hand">Hand to check for the required pose.</param>
+ /// <returns>True if the given hand's index finger tip is farther from the wrist than the index intermediate joint, false otherwise.</returns>
+ static bool IsIndexExtended(XRHand hand)
+ {
+ if (!(hand.GetJoint(XRHandJointID.Wrist).TryGetPose(out var wristPose) &&
+ hand.GetJoint(XRHandJointID.IndexTip).TryGetPose(out var tipPose) &&
+ hand.GetJoint(XRHandJointID.IndexIntermediate).TryGetPose(out var intermediatePose)))
+ {
+ return false;
+ }
+
+ var wristToTip = tipPose.position - wristPose.position;
+ var wristToIntermediate = intermediatePose.position - wristPose.position;
+ return wristToTip.sqrMagnitude > wristToIntermediate.sqrMagnitude;
+ }
+
+ /// <summary>
+ /// Returns true if the given hand's middle finger tip is closer to the wrist than the middle proximal joint.
+ /// </summary>
+ /// <param name="hand">Hand to check for the required pose.</param>
+ /// <returns>True if the given hand's middle finger tip is closer to the wrist than the middle proximal joint, false otherwise.</returns>
+ static bool IsMiddleGrabbing(XRHand hand)
+ {
+ if (!(hand.GetJoint(XRHandJointID.Wrist).TryGetPose(out var wristPose) &&
+ hand.GetJoint(XRHandJointID.MiddleTip).TryGetPose(out var tipPose) &&
+ hand.GetJoint(XRHandJointID.MiddleProximal).TryGetPose(out var proximalPose)))
+ {
+ return false;
+ }
+
+ var wristToTip = tipPose.position - wristPose.position;
+ var wristToProximal = proximalPose.position - wristPose.position;
+ return wristToProximal.sqrMagnitude >= wristToTip.sqrMagnitude;
+ }
+
+ /// <summary>
+ /// Returns true if the given hand's ring finger tip is closer to the wrist than the ring proximal joint.
+ /// </summary>
+ /// <param name="hand">Hand to check for the required pose.</param>
+ /// <returns>True if the given hand's ring finger tip is closer to the wrist than the ring proximal joint, false otherwise.</returns>
+ static bool IsRingGrabbing(XRHand hand)
+ {
+ if (!(hand.GetJoint(XRHandJointID.Wrist).TryGetPose(out var wristPose) &&
+ hand.GetJoint(XRHandJointID.RingTip).TryGetPose(out var tipPose) &&
+ hand.GetJoint(XRHandJointID.RingProximal).TryGetPose(out var proximalPose)))
+ {
+ return false;
+ }
+
+ var wristToTip = tipPose.position - wristPose.position;
+ var wristToProximal = proximalPose.position - wristPose.position;
+ return wristToProximal.sqrMagnitude >= wristToTip.sqrMagnitude;
+ }
+
+ /// <summary>
+ /// Returns true if the given hand's little finger tip is closer to the wrist than the little proximal joint.
+ /// </summary>
+ /// <param name="hand">Hand to check for the required pose.</param>
+ /// <returns>True if the given hand's little finger tip is closer to the wrist than the little proximal joint, false otherwise.</returns>
+ static bool IsLittleGrabbing(XRHand hand)
+ {
+ if (!(hand.GetJoint(XRHandJointID.Wrist).TryGetPose(out var wristPose) &&
+ hand.GetJoint(XRHandJointID.LittleTip).TryGetPose(out var tipPose) &&
+ hand.GetJoint(XRHandJointID.LittleProximal).TryGetPose(out var proximalPose)))
+ {
+ return false;
+ }
+
+ var wristToTip = tipPose.position - wristPose.position;
+ var wristToProximal = proximalPose.position - wristPose.position;
+ return wristToProximal.sqrMagnitude >= wristToTip.sqrMagnitude;
+ }
+
+ void StartPokeGesture()
+ {
+ m_IsPoking = true;
+ m_PokeGestureStarted.Invoke();
+ }
+
+ void EndPokeGesture()
+ {
+ m_IsPoking = false;
+ m_PokeGestureEnded.Invoke();
+ }
+#endif
+ }
+}