From 8263edd59284aba390aca011d25b79efecef4c48 Mon Sep 17 00:00:00 2001 From: pryazha Date: Wed, 2 Jul 2025 08:46:23 -0700 Subject: init --- .../Scripts/PokeGestureDetector.cs | 200 +++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 Assets/Samples/XR Interaction Toolkit/3.1.2/Hands Interaction Demo/Scripts/PokeGestureDetector.cs (limited to 'Assets/Samples/XR Interaction Toolkit/3.1.2/Hands Interaction Demo/Scripts/PokeGestureDetector.cs') 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 +{ + /// + /// Behavior that provides events for when an 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. + /// + 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 s_Subsystems = new List(); +#endif + + /// + /// See . + /// + 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 + } + + /// + /// See . + /// + 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(); + } + + /// + /// Determines whether one or more bit fields are set in the flags. + /// Non-boxing version of HasFlag for . + /// + /// The flags enum instance. + /// The flag to check if set. + /// Returns if the bit field or bit fields are set, otherwise returns . + static bool HasUpdateSuccessFlag(XRHandSubsystem.UpdateSuccessFlags successFlags, XRHandSubsystem.UpdateSuccessFlags successFlag) + { + return (successFlags & successFlag) == successFlag; + } + + /// + /// Returns true if the given hand's index finger tip is farther from the wrist than the index intermediate joint. + /// + /// Hand to check for the required pose. + /// True if the given hand's index finger tip is farther from the wrist than the index intermediate joint, false otherwise. + 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; + } + + /// + /// Returns true if the given hand's middle finger tip is closer to the wrist than the middle proximal joint. + /// + /// Hand to check for the required pose. + /// True if the given hand's middle finger tip is closer to the wrist than the middle proximal joint, false otherwise. + 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; + } + + /// + /// Returns true if the given hand's ring finger tip is closer to the wrist than the ring proximal joint. + /// + /// Hand to check for the required pose. + /// True if the given hand's ring finger tip is closer to the wrist than the ring proximal joint, false otherwise. + 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; + } + + /// + /// Returns true if the given hand's little finger tip is closer to the wrist than the little proximal joint. + /// + /// Hand to check for the required pose. + /// True if the given hand's little finger tip is closer to the wrist than the little proximal joint, false otherwise. + 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 + } +} -- cgit v1.2.3-70-g09d2