using System.Collections; using System.Collections.Generic; using UnityEngine; namespace com.rfilkov.kinect { /// /// This interface needs to be implemented by all Kinect gesture listeners /// public interface GestureListenerInterface { /// /// Invoked when a new user is detected. Here you can start gesture tracking by invoking KinectManager.DetectGesture()-function. /// /// User ID /// User index void UserDetected(ulong userId, int userIndex); /// /// Invoked when a user gets lost. All tracked gestures for this user are cleared automatically. /// /// User ID /// User index void UserLost(ulong userId, int userIndex); /// /// Invoked when a gesture is in progress. /// /// User ID /// User index /// Gesture type /// Gesture progress [0..1] /// Joint type /// Normalized viewport position void GestureInProgress(ulong userId, int userIndex, GestureType gesture, float progress, KinectInterop.JointType joint, Vector3 screenPos); /// /// Invoked if a gesture is completed. /// /// true, if the gesture detection must be restarted, false otherwise. /// User ID /// User index /// Gesture type /// Joint type /// Normalized viewport position bool GestureCompleted(ulong userId, int userIndex, GestureType gesture, KinectInterop.JointType joint, Vector3 screenPos); /// /// Invoked if a gesture is cancelled. /// /// true, if the gesture detection must be retarted, false otherwise. /// User ID /// User index /// Gesture type /// Joint type bool GestureCancelled(ulong userId, int userIndex, GestureType gesture, KinectInterop.JointType joint); } /// /// Kinect gesture types. /// public enum GestureType { None = 0, RaiseRightHand, RaiseLeftHand, Psi, Tpose, Stop, Wave, SwipeLeft, SwipeRight, SwipeUp, SwipeDown, ZoomIn, ZoomOut, Wheel, Jump, Squat, Push, Pull, ShoulderLeftFront, ShoulderRightFront, LeanLeft, LeanRight, LeanForward, LeanBack, KickLeft, KickRight, Run, RaisedRightHorizontalLeftHand, // by Andrzej W RaisedLeftHorizontalRightHand, TouchRightElbow, // suggested by Nayden N. TouchLeftElbow, UserGesture1 = 101, UserGesture2 = 102, UserGesture3 = 103, UserGesture4 = 104, UserGesture5 = 105, UserGesture6 = 106, UserGesture7 = 107, UserGesture8 = 108, UserGesture9 = 109, UserGesture10 = 110, } /// /// Kinect gesture manager is the component that tracks and processes the user gestures. /// public class KinectGestureManager : MonoBehaviour { /// /// Programmatic gesture data container. /// public struct GestureData { public ulong userId; public GestureType gesture; public int state; public float timestamp; public int joint; public Vector3 jointPos; public Vector3 screenPos; public float tagFloat; public Vector3 tagVector; public Vector3 tagVector2; public float progress; public bool complete; public bool cancelled; public List checkForGestures; public float startTrackingAtTime; } [Tooltip("Minimum time between gesture detections (in seconds).")] public float minTimeBetweenGestures = 0.7f; [Tooltip("List of the gesture listeners in the scene. If the list is empty, the available gesture listeners will be detected at the scene start up.")] public List gestureListeners = new List(); [Tooltip("UI-Text to display the status of the currently tracked gestures.")] public UnityEngine.UI.Text gestureDebugText; // Gesture related constants, variables and functions protected int leftHandIndex; protected int rightHandIndex; protected int leftFingerIndex; protected int rightFingerIndex; protected int leftElbowIndex; protected int rightElbowIndex; protected int leftShoulderIndex; protected int rightShoulderIndex; protected int leftClavicleIndex; protected int rightClavicleIndex; protected int hipCenterIndex; protected int neckIndex; protected int leftHipIndex; protected int rightHipIndex; protected int leftKneeIndex; protected int rightKneeIndex; protected int leftAnkleIndex; protected int rightAnkleIndex; // gestures data and parameters protected Dictionary> playerGesturesData = new Dictionary>(); protected Dictionary gesturesTrackingAtTime = new Dictionary(); /// /// Adds a gesture to the list of detected gestures for the specified user. /// /// User ID /// Gesture type public void DetectGesture(ulong UserId, GestureType gesture) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : new List(); int index = GetGestureIndex(gesture, ref gesturesData); if (index >= 0) { DeleteGesture(UserId, gesture); } GestureData gestureData = new GestureData(); gestureData.userId = UserId; gestureData.gesture = gesture; gestureData.state = 0; gestureData.joint = 0; gestureData.progress = 0f; gestureData.complete = false; gestureData.cancelled = false; gestureData.checkForGestures = new List(); switch (gesture) { case GestureType.ZoomIn: gestureData.checkForGestures.Add(GestureType.ZoomOut); gestureData.checkForGestures.Add(GestureType.Wheel); break; case GestureType.ZoomOut: gestureData.checkForGestures.Add(GestureType.ZoomIn); gestureData.checkForGestures.Add(GestureType.Wheel); break; case GestureType.Wheel: gestureData.checkForGestures.Add(GestureType.ZoomIn); gestureData.checkForGestures.Add(GestureType.ZoomOut); break; } gesturesData.Add(gestureData); playerGesturesData[UserId] = gesturesData; if (!gesturesTrackingAtTime.ContainsKey(UserId)) { gesturesTrackingAtTime[UserId] = 0f; } } /// /// Resets the gesture state for the given gesture of the specified user. /// /// true, if gesture was reset, false otherwise. /// User ID /// Gesture type public bool ResetGesture(ulong UserId, GestureType gesture) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; int index = gesturesData != null ? GetGestureIndex(gesture, ref gesturesData) : -1; if (index < 0) return false; GestureData gestureData = gesturesData[index]; gestureData.state = 0; gestureData.joint = 0; gestureData.progress = 0f; gestureData.complete = false; gestureData.cancelled = false; gestureData.startTrackingAtTime = Time.realtimeSinceStartup + KinectInterop.Constants.MinTimeBetweenSameGestures; gesturesData[index] = gestureData; playerGesturesData[UserId] = gesturesData; return true; } /// /// Resets the gesture states for all gestures of the specified user. /// /// User ID public void ResetPlayerGestures(ulong UserId) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; if (gesturesData != null) { int listSize = gesturesData.Count; for (int i = 0; i < listSize; i++) { ResetGesture(UserId, gesturesData[i].gesture); } } } /// /// Deletes the gesture for the specified user. /// /// true, if gesture was deleted, false otherwise. /// User ID /// Gesture type public bool DeleteGesture(ulong UserId, GestureType gesture) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; int index = gesturesData != null ? GetGestureIndex(gesture, ref gesturesData) : -1; if (index < 0) return false; gesturesData.RemoveAt(index); playerGesturesData[UserId] = gesturesData; return true; } /// /// Deletes all gestures for the specified user. /// /// User ID public void ClearUserGestures(ulong UserId) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; if (gesturesData != null) { gesturesData.Clear(); playerGesturesData[UserId] = gesturesData; } } /// /// Gets the list of gestures for the specified user. /// /// The gestures list. /// User ID public List GetGesturesList(ulong UserId) { List list = new List(); List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; if (gesturesData != null) { foreach (GestureData data in gesturesData) list.Add(data.gesture); } return list; } /// /// Gets the gestures count for the specified user. /// /// The gestures count. /// User ID public int GetGesturesCount(ulong UserId) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; if (gesturesData != null) { return gesturesData.Count; } return 0; } /// /// Gets the gesture at the specified index for the given user. /// /// The gesture at specified index. /// User ID /// Index public GestureType GetGestureAtIndex(ulong UserId, int i) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; if (gesturesData != null) { if (i >= 0 && i < gesturesData.Count) { return gesturesData[i].gesture; } } return GestureType.None; } /// /// Determines whether the given gesture is in the list of gestures for the specified user. /// /// true if the gesture is in the list of gestures for the specified user; otherwise, false. /// User ID /// Gesture type public bool IsTrackingGesture(ulong UserId, GestureType gesture) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; int index = gesturesData != null ? GetGestureIndex(gesture, ref gesturesData) : -1; return index >= 0; } /// /// Determines whether the given gesture for the specified user is complete. /// /// true if the gesture is complete; otherwise, false. /// User ID /// Gesture type /// If set to true, resets the gesture state. public bool IsGestureComplete(ulong UserId, GestureType gesture, bool bResetOnComplete) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; int index = gesturesData != null ? GetGestureIndex(gesture, ref gesturesData) : -1; if (index >= 0) { GestureData gestureData = gesturesData[index]; if (bResetOnComplete && gestureData.complete) { ResetPlayerGestures(UserId); return true; } return gestureData.complete; } return false; } /// /// Determines whether the given gesture for the specified user is canceled. /// /// true if the gesture is canceled; otherwise, false. /// User ID /// Gesture type public bool IsGestureCancelled(ulong UserId, GestureType gesture) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; int index = gesturesData != null ? GetGestureIndex(gesture, ref gesturesData) : -1; if (index >= 0) { GestureData gestureData = gesturesData[index]; return gestureData.cancelled; } return false; } /// /// Gets the progress (in range [0, 1]) of the given gesture for the specified user. /// /// The gesture progress. /// User ID /// Gesture type public float GetGestureProgress(ulong UserId, GestureType gesture) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; int index = gesturesData != null ? GetGestureIndex(gesture, ref gesturesData) : -1; if (index >= 0) { GestureData gestureData = gesturesData[index]; return gestureData.progress; } return 0f; } /// /// Gets the normalized screen position of the given gesture for the specified user. /// /// The normalized screen position. /// User ID /// Gesture type public Vector3 GetGestureScreenPos(ulong UserId, GestureType gesture) { List gesturesData = playerGesturesData.ContainsKey(UserId) ? playerGesturesData[UserId] : null; int index = gesturesData != null ? GetGestureIndex(gesture, ref gesturesData) : -1; if (index >= 0) { GestureData gestureData = gesturesData[index]; return gestureData.screenPos; } return Vector3.zero; } /// /// Locate the available gesture listeners. /// public void RefreshGestureListeners() { gestureListeners.Clear(); MonoBehaviour[] monoScripts = FindObjectsOfType() as MonoBehaviour[]; foreach (MonoBehaviour monoScript in monoScripts) { if ((monoScript is GestureListenerInterface) && monoScript.enabled) { //GestureListenerInterface gl = (GestureListenerInterface)monoScript; gestureListeners.Add(monoScript); } } } /// /// Invoked when a new user gets detected. /// /// User ID /// User index public void UserWasAdded(ulong userId, int userIndex) { //Debug.Log("GM - UserAdded: " + userId); //// add the gestures to be detected by all users, if any //foreach (GestureType gesture in playerCommonGestures) //{ // DetectGesture(userId, gesture); //} // notify all gesture listeners of the newly detected user foreach (GestureListenerInterface listener in gestureListeners) { if (listener != null) { listener.UserDetected(userId, userIndex); } } } /// /// Invoked when user was removed. /// /// User ID /// User index public void UserWasRemoved(ulong userId, int userIndex) { //Debug.Log("GM - UserRemoved: " + userId); // notify all gesture listeners for losing this user foreach (GestureListenerInterface listener in gestureListeners) { if (listener != null) { listener.UserLost(userId, userIndex); } } // clear the user gestures ClearUserGestures(userId); } /// /// Updates the progress of the given user's gestures. /// /// User ID /// Reference to the KinectManager public void UpdateUserGestures(ulong userId, KinectManager kinectManager) { if (!playerGesturesData.ContainsKey(userId)) return; //Debug.Log("GM - UpdateGestures for user: " + userId); // Check for player's gestures CheckForGestures(userId, kinectManager); // Check for complete gestures List gesturesData = playerGesturesData[userId]; int userIndex = kinectManager.GetUserIndexById(userId); for (int g = 0; g < gesturesData.Count; g++) { GestureData gestureData = gesturesData[g]; if (gestureData.complete) { foreach (GestureListenerInterface listener in gestureListeners) { if (listener != null && listener.GestureCompleted(userId, userIndex, gestureData.gesture, (KinectInterop.JointType)gestureData.joint, gestureData.screenPos)) { ResetPlayerGestures(userId); } } } else if (gestureData.cancelled) { foreach (GestureListenerInterface listener in gestureListeners) { if (listener != null && listener.GestureCancelled(userId, userIndex, gestureData.gesture, (KinectInterop.JointType)gestureData.joint)) { ResetGesture(userId, gestureData.gesture); } } } else if (gestureData.progress >= 0.1f) { foreach (GestureListenerInterface listener in gestureListeners) { if (listener != null) { listener.GestureInProgress(userId, userIndex, gestureData.gesture, gestureData.progress, (KinectInterop.JointType)gestureData.joint, gestureData.screenPos); } } } //gesturesData[g] = gestureData; } } protected void Start() { // locate the available gesture listeners RefreshGestureListeners(); } // Estimates the current state of the defined gestures protected void CheckForGestures(ulong UserId, KinectManager kinectManager) { if (!playerGesturesData.ContainsKey(UserId) || !gesturesTrackingAtTime.ContainsKey(UserId)) return; // check for gestures if (Time.realtimeSinceStartup >= gesturesTrackingAtTime[UserId]) { // get joint positions and tracking int iAllJointsCount = (int)KinectInterop.JointType.Count; bool[] playerJointsTracked = new bool[iAllJointsCount]; Vector3[] playerJointsPos = new Vector3[iAllJointsCount]; int[] aiNeededJointIndexes = GetNeededJointIndexes(); int iNeededJointsCount = aiNeededJointIndexes.Length; for (int i = 0; i < iNeededJointsCount; i++) { int joint = aiNeededJointIndexes[i]; if (joint >= 0) { playerJointsTracked[joint] = kinectManager.IsJointTracked(UserId, joint); playerJointsPos[joint] = kinectManager.GetJointPosition(UserId, joint); } } // check for gestures List gesturesData = playerGesturesData[UserId]; int listGestureSize = gesturesData.Count; float timestampNow = Time.realtimeSinceStartup; string sDebugGestures = string.Empty; // "Tracked Gestures:\n"; for (int g = 0; g < listGestureSize; g++) { GestureData gestureData = gesturesData[g]; if ((timestampNow >= gestureData.startTrackingAtTime) && !IsConflictingGestureInProgress(gestureData, ref gesturesData)) { CheckForGesture(UserId, ref gestureData, Time.realtimeSinceStartup, ref playerJointsPos, ref playerJointsTracked); gesturesData[g] = gestureData; if (gestureData.complete) { gesturesTrackingAtTime[UserId] = timestampNow + minTimeBetweenGestures; } if (UserId == kinectManager.GetPrimaryUserID()) { sDebugGestures += string.Format("{0} - state: {1}, time: {2:F1}, progress: {3}%\n", gestureData.gesture, gestureData.state, gestureData.timestamp, (int)(gestureData.progress * 100 + 0.5f)); } } } playerGesturesData[UserId] = gesturesData; if (gestureDebugText && (UserId == kinectManager.GetPrimaryUserID())) { for (int i = 0; i < iNeededJointsCount; i++) { int joint = aiNeededJointIndexes[i]; sDebugGestures += string.Format("\n {0}: {1}", (KinectInterop.JointType)joint, playerJointsTracked[joint] ? playerJointsPos[joint].ToString() : ""); } gestureDebugText.text = sDebugGestures; } } } private bool IsConflictingGestureInProgress(GestureData gestureData, ref List gesturesData) { foreach (GestureType gesture in gestureData.checkForGestures) { int index = GetGestureIndex(gesture, ref gesturesData); if (index >= 0) { if (gesturesData[index].progress > 0f) return true; } } return false; } // return the index of gesture in the list, or -1 if not found private int GetGestureIndex(GestureType gesture, ref List gesturesData) { int listSize = gesturesData.Count; for (int i = 0; i < listSize; i++) { if (gesturesData[i].gesture == gesture) return i; } return -1; } /// /// Gets the list of gesture joint indexes. /// /// The needed joint indexes. public virtual int[] GetNeededJointIndexes() { leftHandIndex = (int)KinectInterop.JointType.HandLeft; rightHandIndex = (int)KinectInterop.JointType.HandRight; leftFingerIndex = (int)KinectInterop.JointType.HandLeft; rightFingerIndex = (int)KinectInterop.JointType.HandRight; leftElbowIndex = (int)KinectInterop.JointType.ElbowLeft; rightElbowIndex = (int)KinectInterop.JointType.ElbowRight; leftShoulderIndex = (int)KinectInterop.JointType.ShoulderLeft; rightShoulderIndex = (int)KinectInterop.JointType.ShoulderRight; leftClavicleIndex = (int)KinectInterop.JointType.ClavicleLeft; rightClavicleIndex = (int)KinectInterop.JointType.ClavicleRight; hipCenterIndex = (int)KinectInterop.JointType.Pelvis; neckIndex = (int)KinectInterop.JointType.Neck; leftHipIndex = (int)KinectInterop.JointType.HipLeft; rightHipIndex = (int)KinectInterop.JointType.HipRight; leftKneeIndex = (int)KinectInterop.JointType.KneeLeft; rightKneeIndex = (int)KinectInterop.JointType.KneeRight; leftAnkleIndex = (int)KinectInterop.JointType.AnkleLeft; rightAnkleIndex = (int)KinectInterop.JointType.AnkleRight; int[] neededJointIndexes = { leftHandIndex, rightHandIndex, leftFingerIndex, rightFingerIndex, leftElbowIndex, rightElbowIndex, leftShoulderIndex, rightShoulderIndex, leftClavicleIndex, rightClavicleIndex, hipCenterIndex, neckIndex, leftHipIndex, rightHipIndex, leftKneeIndex, rightKneeIndex, leftAnkleIndex, rightAnkleIndex }; return neededJointIndexes; } // sets basic parameters of the gesture data protected void SetGestureJoint(ref GestureData gestureData, float timestamp, int joint, Vector3 jointPos) { gestureData.joint = joint; gestureData.jointPos = jointPos; gestureData.timestamp = timestamp; gestureData.state++; } // marks the gesture data as cancelled gesture protected void SetGestureCancelled(ref GestureData gestureData) { gestureData.state = 0; gestureData.progress = 0f; gestureData.cancelled = true; } // checks if the pose persists for the whole duration set protected void CheckPoseComplete(ref GestureData gestureData, float timestamp, Vector3 jointPos, bool isInPose, float durationToComplete) { if (isInPose) { float timeLeft = timestamp - gestureData.timestamp; gestureData.progress = durationToComplete > 0f ? Mathf.Clamp01(timeLeft / durationToComplete) : 1.0f; if (timeLeft >= durationToComplete) { gestureData.timestamp = timestamp; gestureData.jointPos = jointPos; gestureData.state++; gestureData.complete = true; } } else { SetGestureCancelled(ref gestureData); } } // sets gesture data current screen coords (useful for many gestures) protected void SetScreenPos(ulong userId, ref GestureData gestureData, ref Vector3[] jointsPos, ref bool[] jointsTracked) { Vector3 handPos = jointsPos[rightHandIndex]; bool calculateCoords = false; if (gestureData.joint == rightHandIndex) { if (jointsTracked[rightHandIndex] /**&& jointsTracked[rightElbowIndex] && jointsTracked[rightShoulderIndex]*/) { calculateCoords = true; } } else if (gestureData.joint == leftHandIndex) { if (jointsTracked[leftHandIndex] /**&& jointsTracked[leftElbowIndex] && jointsTracked[leftShoulderIndex]*/) { handPos = jointsPos[leftHandIndex]; calculateCoords = true; } } if (calculateCoords) { if (jointsTracked[hipCenterIndex] && jointsTracked[leftClavicleIndex] && jointsTracked[rightClavicleIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex]) { Vector3 shoulderCenterPos = (jointsPos[leftClavicleIndex] + jointsPos[rightClavicleIndex]) / 2f; Vector3 shoulderToHips = shoulderCenterPos - jointsPos[hipCenterIndex]; Vector3 rightToLeft = jointsPos[rightShoulderIndex] - jointsPos[leftShoulderIndex]; gestureData.tagVector2.x = rightToLeft.x; // * 1.2f; gestureData.tagVector2.y = shoulderToHips.y; // * 1.2f; if (gestureData.joint == rightHandIndex) { gestureData.tagVector.x = jointsPos[rightShoulderIndex].x - gestureData.tagVector2.x / 2f; gestureData.tagVector.y = jointsPos[hipCenterIndex].y; } else { gestureData.tagVector.x = jointsPos[leftShoulderIndex].x - gestureData.tagVector2.x / 2f; gestureData.tagVector.y = jointsPos[hipCenterIndex].y; } } if (gestureData.tagVector2.x != 0 && gestureData.tagVector2.y != 0) { Vector3 relHandPos = handPos - gestureData.tagVector; gestureData.screenPos.x = Mathf.Clamp01(relHandPos.x / gestureData.tagVector2.x); gestureData.screenPos.y = Mathf.Clamp01(relHandPos.y / gestureData.tagVector2.y); } } } // sets the zoom factor value as screenPos.z (for zoom-in and zoom-out gestures) protected void SetZoomFactor(ulong userId, ref GestureData gestureData, float initialZoom, ref Vector3[] jointsPos, ref bool[] jointsTracked) { Vector3 vectorZooming = jointsPos[rightHandIndex] - jointsPos[leftHandIndex]; if (gestureData.tagFloat == 0f || gestureData.userId != userId) { gestureData.tagFloat = 0.5f; // this is 100% } float distZooming = vectorZooming.magnitude; gestureData.screenPos.z = initialZoom + (distZooming / gestureData.tagFloat); } // sets the wheel rotation value as screenPos.z (for wheel-gesture) protected void SetWheelRotation(ulong userId, ref GestureData gestureData, Vector3 initialPos, Vector3 currentPos) { float angle = Vector3.Angle(initialPos, currentPos) * Mathf.Sign(currentPos.y - initialPos.y); gestureData.screenPos.z = angle; } /// /// Estimate the state and progress of the given gesture. /// /// User ID /// Gesture-data structure /// Current time /// Joints-position array /// Joints-tracked array public virtual void CheckForGesture(ulong userId, ref GestureData gestureData, float timestamp, ref Vector3[] jointsPos, ref bool[] jointsTracked) { if (gestureData.complete) return; float bandTopY = jointsPos[rightShoulderIndex].y > jointsPos[leftShoulderIndex].y ? jointsPos[rightShoulderIndex].y : jointsPos[leftShoulderIndex].y; float bandBotY = jointsPos[rightHipIndex].y < jointsPos[leftHipIndex].y ? jointsPos[rightHipIndex].y : jointsPos[leftHipIndex].y; float bandCenter = (bandTopY + bandBotY) / 2f; float bandSize = (bandTopY - bandBotY); float gestureTop = bandCenter + bandSize * 1.2f / 2f; float gestureBottom = bandCenter - bandSize * 1.3f / 4f; float gestureRight = jointsPos[rightHipIndex].x; float gestureLeft = jointsPos[leftHipIndex].x; switch (gestureData.gesture) { // check for RaiseRightHand case GestureType.RaiseRightHand: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[rightHandIndex] && jointsTracked[leftHandIndex] && jointsTracked[leftShoulderIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftShoulderIndex].y) > 0.1f && (jointsPos[leftHandIndex].y - jointsPos[leftShoulderIndex].y) < 0f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); } break; case 1: // gesture complete bool isInPose = jointsTracked[rightHandIndex] && jointsTracked[leftHandIndex] && jointsTracked[leftShoulderIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftShoulderIndex].y) > 0.1f && (jointsPos[leftHandIndex].y - jointsPos[leftShoulderIndex].y) < 0f; Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, KinectInterop.Constants.PoseCompleteDuration); break; } break; // check for RaiseLeftHand case GestureType.RaiseLeftHand: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[leftHandIndex] && jointsTracked[rightHandIndex] && jointsTracked[rightShoulderIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightShoulderIndex].y) > 0.1f && (jointsPos[rightHandIndex].y - jointsPos[rightShoulderIndex].y) < 0f) { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); } break; case 1: // gesture complete bool isInPose = jointsTracked[leftHandIndex] && jointsTracked[rightHandIndex] && jointsTracked[rightShoulderIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightShoulderIndex].y) > 0.1f && (jointsPos[rightHandIndex].y - jointsPos[rightShoulderIndex].y) < 0f; Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, KinectInterop.Constants.PoseCompleteDuration); break; } break; // check for Psi case GestureType.Psi: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[rightHandIndex] && jointsTracked[leftHandIndex] && jointsTracked[leftClavicleIndex] && jointsTracked[rightClavicleIndex] && (jointsPos[rightHandIndex].y - jointsPos[rightClavicleIndex].y) > 0.1f && (jointsPos[leftHandIndex].y - jointsPos[leftClavicleIndex].y) > 0.1f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); } break; case 1: // gesture complete bool isInPose = jointsTracked[rightHandIndex] && jointsTracked[leftHandIndex] && jointsTracked[leftClavicleIndex] && jointsTracked[rightClavicleIndex] && (jointsPos[rightHandIndex].y - jointsPos[rightClavicleIndex].y) > 0.1f && (jointsPos[leftHandIndex].y - jointsPos[leftClavicleIndex].y) > 0.1f; Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, KinectInterop.Constants.PoseCompleteDuration); break; } break; // check for Tpose case GestureType.Tpose: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[rightHandIndex] && jointsTracked[rightElbowIndex] && jointsTracked[rightShoulderIndex] && Mathf.Abs(jointsPos[rightElbowIndex].y - jointsPos[rightShoulderIndex].y) < 0.1f && // 0.07f Mathf.Abs(jointsPos[rightHandIndex].y - jointsPos[rightElbowIndex].y) < 0.1f && // 0.7f jointsTracked[leftHandIndex] && jointsTracked[leftElbowIndex] && jointsTracked[leftShoulderIndex] && Mathf.Abs(jointsPos[leftElbowIndex].y - jointsPos[leftShoulderIndex].y) < 0.1f && Mathf.Abs(jointsPos[leftHandIndex].y - jointsPos[leftElbowIndex].y) < 0.1f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); } break; case 1: // gesture complete bool isInPose = jointsTracked[rightHandIndex] && jointsTracked[rightElbowIndex] && jointsTracked[rightShoulderIndex] && Mathf.Abs(jointsPos[rightElbowIndex].y - jointsPos[rightShoulderIndex].y) < 0.1f && // 0.7f Mathf.Abs(jointsPos[rightHandIndex].y - jointsPos[rightElbowIndex].y) < 0.1f && // 0.7f jointsTracked[leftHandIndex] && jointsTracked[leftElbowIndex] && jointsTracked[leftShoulderIndex] && Mathf.Abs(jointsPos[leftElbowIndex].y - jointsPos[leftShoulderIndex].y) < 0.1f && Mathf.Abs(jointsPos[leftHandIndex].y - jointsPos[leftElbowIndex].y) < 0.1f; Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, KinectInterop.Constants.PoseCompleteDuration); break; } break; // check for Stop case GestureType.Stop: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[rightHandIndex] && jointsTracked[rightHipIndex] && (jointsPos[rightHandIndex].y - jointsPos[rightHipIndex].y) < 0.2f && (jointsPos[rightHandIndex].x - jointsPos[rightHipIndex].x) >= 0.4f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); } else if (jointsTracked[leftHandIndex] && jointsTracked[leftHipIndex] && (jointsPos[leftHandIndex].y - jointsPos[leftHipIndex].y) < 0.2f && (jointsPos[leftHandIndex].x - jointsPos[leftHipIndex].x) <= -0.4f) { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); } break; case 1: // gesture complete bool isInPose = (gestureData.joint == rightHandIndex) ? (jointsTracked[rightHandIndex] && jointsTracked[rightHipIndex] && (jointsPos[rightHandIndex].y - jointsPos[rightHipIndex].y) < 0.2f && (jointsPos[rightHandIndex].x - jointsPos[rightHipIndex].x) >= 0.4f) : (jointsTracked[leftHandIndex] && jointsTracked[leftHipIndex] && (jointsPos[leftHandIndex].y - jointsPos[leftHipIndex].y) < 0.2f && (jointsPos[leftHandIndex].x - jointsPos[leftHipIndex].x) <= -0.4f); Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, KinectInterop.Constants.PoseCompleteDuration); break; } break; // check for raised right hand & horizontal left hand case GestureType.RaisedRightHorizontalLeftHand: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[rightHandIndex] && jointsTracked[rightShoulderIndex] && // check right hand is straight up (jointsPos[rightHandIndex].y - jointsPos[rightShoulderIndex].y) > 0.5f && // ensure right hand is higher than shoulder Mathf.Abs(jointsPos[rightHandIndex].z - jointsPos[rightShoulderIndex].z) < 0.35f && // ensue hand is vertical straight enough Mathf.Abs(jointsPos[rightHandIndex].x - jointsPos[rightShoulderIndex].x) < 0.35f && // ensue hand is vertical straight enough jointsTracked[leftHandIndex] && jointsTracked[leftShoulderIndex] && // check left hand is straight flat Mathf.Abs(jointsPos[leftHandIndex].y - jointsPos[leftShoulderIndex].y) < 0.25f && // ensure hand and shoulder are on close height (jointsPos[leftHandIndex] - jointsPos[leftShoulderIndex]).sqrMagnitude > 0.25f) // ensure hand and shoulder are horizontal straight enough { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); } break; case 1: // gesture complete bool isInPose = jointsTracked[rightHandIndex] && jointsTracked[rightShoulderIndex] && // check right hand is straight up (jointsPos[rightHandIndex].y - jointsPos[rightShoulderIndex].y) > 0.5f && // ensure right hand is higher than shoulder Mathf.Abs(jointsPos[rightHandIndex].z - jointsPos[rightShoulderIndex].z) < 0.35f && // ensue hand is vertical straight enough Mathf.Abs(jointsPos[rightHandIndex].x - jointsPos[rightShoulderIndex].x) < 0.35f && // ensue hand is vertical straight enough jointsTracked[leftHandIndex] && jointsTracked[leftShoulderIndex] && // check left hand is straight flat Mathf.Abs(jointsPos[leftHandIndex].y - jointsPos[leftShoulderIndex].y) < 0.25f && // ensure hand and shoulder are on close height (jointsPos[leftHandIndex] - jointsPos[leftShoulderIndex]).sqrMagnitude > 0.25f; // ensure hand and shoulder are horizontal straight enough Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, KinectInterop.Constants.PoseCompleteDuration); break; } break; // check for raised left hand & horizontal right hand case GestureType.RaisedLeftHorizontalRightHand: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[leftHandIndex] && jointsTracked[leftShoulderIndex] && // check left hand is straight up (jointsPos[leftHandIndex].y - jointsPos[leftShoulderIndex].y) > 0.5f && // ensure left hand is higher than shoulder Mathf.Abs(jointsPos[leftHandIndex].z - jointsPos[leftShoulderIndex].z) < 0.35f && // ensue hand is vertical straight enough Mathf.Abs(jointsPos[leftHandIndex].x - jointsPos[leftShoulderIndex].x) < 0.35f && // ensue hand is vertical straight enough jointsTracked[rightHandIndex] && jointsTracked[rightShoulderIndex] && // check right hand is straight flat Mathf.Abs(jointsPos[rightHandIndex].y - jointsPos[rightShoulderIndex].y) < 0.25f && // ensure hand and shoulder are on close height (jointsPos[rightHandIndex] - jointsPos[rightShoulderIndex]).sqrMagnitude > 0.25f) // ensure hand and shoulder are horizontal straight enough { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); } break; case 1: // gesture complete bool isInPose = jointsTracked[leftHandIndex] && jointsTracked[leftShoulderIndex] && // check left hand is straight up (jointsPos[leftHandIndex].y - jointsPos[leftShoulderIndex].y) > 0.5f && // ensure left hand is higher than shoulder Mathf.Abs(jointsPos[leftHandIndex].z - jointsPos[leftShoulderIndex].z) < 0.35f && // ensue hand is vertical straight enough Mathf.Abs(jointsPos[leftHandIndex].x - jointsPos[leftShoulderIndex].x) < 0.35f && // ensue hand is vertical straight enough jointsTracked[rightHandIndex] && jointsTracked[rightShoulderIndex] && // check right hand is straight flat Mathf.Abs(jointsPos[rightHandIndex].y - jointsPos[rightShoulderIndex].y) < 0.25f && // ensure hand and shoulder are on close height (jointsPos[rightHandIndex] - jointsPos[rightShoulderIndex]).sqrMagnitude > 0.25f; // ensure hand and shoulder are horizontal straight enough Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, KinectInterop.Constants.PoseCompleteDuration); break; } break; // check for TouchedRightElbow case GestureType.TouchRightElbow: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[leftFingerIndex] && jointsTracked[rightElbowIndex] && Vector3.Distance(jointsPos[leftFingerIndex], jointsPos[rightElbowIndex]) <= 0.12f) { SetGestureJoint(ref gestureData, timestamp, leftFingerIndex, jointsPos[leftFingerIndex]); } //Debug.Log ("TRE0 - Distance: " + Vector3.Distance(jointsPos[leftFingerIndex], jointsPos[rightElbowIndex])); break; case 1: // gesture complete bool isInPose = jointsTracked[leftFingerIndex] && jointsTracked[rightElbowIndex] && Vector3.Distance(jointsPos[leftFingerIndex], jointsPos[rightElbowIndex]) <= 0.12f; //Debug.Log ("TRE1 - Distance: " + Vector3.Distance(jointsPos[leftFingerIndex], jointsPos[rightElbowIndex]) + ", progress: " + gestureData.progress); Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 1.5f /**KinectInterop.Constants.PoseCompleteDuration*/); break; } break; // check for TouchedLeftElbow case GestureType.TouchLeftElbow: switch (gestureData.state) { case 0: // gesture detection if (jointsTracked[rightFingerIndex] && jointsTracked[leftElbowIndex] && Vector3.Distance(jointsPos[rightFingerIndex], jointsPos[leftElbowIndex]) <= 0.12f) { SetGestureJoint(ref gestureData, timestamp, rightFingerIndex, jointsPos[rightFingerIndex]); } //Debug.Log ("TLE0 - Distance: " + Vector3.Distance(jointsPos[rightFingerIndex], jointsPos[leftElbowIndex])); break; case 1: // gesture complete bool isInPose = jointsTracked[rightFingerIndex] && jointsTracked[leftElbowIndex] && Vector3.Distance(jointsPos[rightFingerIndex], jointsPos[leftElbowIndex]) <= 0.12f; //Debug.Log ("TLE1- Distance: " + Vector3.Distance(jointsPos[rightFingerIndex], jointsPos[leftElbowIndex])); Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 1.5f /**KinectInterop.Constants.PoseCompleteDuration*/); break; } break; // check for Wave case GestureType.Wave: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[rightHandIndex] && jointsTracked[rightElbowIndex] && (jointsPos[rightHandIndex].y - jointsPos[rightElbowIndex].y) > 0.1f && (jointsPos[rightHandIndex].x - jointsPos[rightElbowIndex].x) > 0.05f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.progress = 0.3f; } else if (jointsTracked[leftHandIndex] && jointsTracked[leftElbowIndex] && (jointsPos[leftHandIndex].y - jointsPos[leftElbowIndex].y) > 0.1f && (jointsPos[leftHandIndex].x - jointsPos[leftElbowIndex].x) < -0.05f) { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); gestureData.progress = 0.3f; } break; case 1: // gesture - phase 2 if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = gestureData.joint == rightHandIndex ? jointsTracked[rightHandIndex] && jointsTracked[rightElbowIndex] && (jointsPos[rightHandIndex].y - jointsPos[rightElbowIndex].y) > 0.1f && (jointsPos[rightHandIndex].x - jointsPos[rightElbowIndex].x) < -0.05f : jointsTracked[leftHandIndex] && jointsTracked[leftElbowIndex] && (jointsPos[leftHandIndex].y - jointsPos[leftElbowIndex].y) > 0.1f && (jointsPos[leftHandIndex].x - jointsPos[leftElbowIndex].x) > 0.05f; if (isInPose) { gestureData.timestamp = timestamp; gestureData.state++; gestureData.progress = 0.7f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; case 2: // gesture phase 3 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = gestureData.joint == rightHandIndex ? jointsTracked[rightHandIndex] && jointsTracked[rightElbowIndex] && (jointsPos[rightHandIndex].y - jointsPos[rightElbowIndex].y) > 0.1f && (jointsPos[rightHandIndex].x - jointsPos[rightElbowIndex].x) > 0.05f : jointsTracked[leftHandIndex] && jointsTracked[leftElbowIndex] && (jointsPos[leftHandIndex].y - jointsPos[leftElbowIndex].y) > 0.1f && (jointsPos[leftHandIndex].x - jointsPos[leftElbowIndex].x) < -0.05f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for SwipeLeft case GestureType.SwipeLeft: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[rightHandIndex].y >= gestureBottom && jointsPos[rightHandIndex].y <= gestureTop && jointsPos[rightHandIndex].x >= gestureRight /**&& jointsPos[rightHandIndex].x > gestureLeft*/) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.progress = 0.1f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) <= 1.0f) { bool isInPose = jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[rightHandIndex].y >= gestureBottom && jointsPos[rightHandIndex].y <= gestureTop && jointsPos[rightHandIndex].x <= gestureLeft; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } else if (jointsPos[rightHandIndex].x <= gestureRight) { float gestureSize = gestureRight - gestureLeft; gestureData.progress = gestureSize > 0.01f ? (gestureRight - jointsPos[rightHandIndex].x) / gestureSize : 0f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for SwipeRight case GestureType.SwipeRight: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[leftHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[leftHandIndex].y >= gestureBottom && jointsPos[leftHandIndex].y <= gestureTop && jointsPos[leftHandIndex].x <= gestureLeft /**&& jointsPos[leftHandIndex].x < gestureRight*/) { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); gestureData.progress = 0.1f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) <= 1.0f) { bool isInPose = jointsTracked[leftHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[leftHandIndex].y >= gestureBottom && jointsPos[leftHandIndex].y <= gestureTop && jointsPos[leftHandIndex].x >= gestureRight; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } else if (jointsPos[leftHandIndex].x >= gestureLeft) { float gestureSize = gestureRight - gestureLeft; gestureData.progress = gestureSize > 0.01f ? (jointsPos[leftHandIndex].x - gestureLeft) / gestureSize : 0f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for SwipeUp case GestureType.SwipeUp: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[rightHandIndex] && jointsTracked[leftElbowIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftElbowIndex].y) < 0f && (jointsPos[rightHandIndex].y - jointsPos[leftElbowIndex].y) > -0.15f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.progress = 0.5f; } else if (jointsTracked[leftHandIndex] && jointsTracked[rightElbowIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightElbowIndex].y) < 0f && (jointsPos[leftHandIndex].y - jointsPos[rightElbowIndex].y) > -0.15f) { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = gestureData.joint == rightHandIndex ? jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftShoulderIndex].y) > -0.05f && Mathf.Abs(jointsPos[rightHandIndex].x - gestureData.jointPos.x) <= 0.15f : jointsTracked[leftHandIndex] && jointsTracked[rightShoulderIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightShoulderIndex].y) > -0.05f && Mathf.Abs(jointsPos[leftHandIndex].x - gestureData.jointPos.x) <= 0.15f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for SwipeDown case GestureType.SwipeDown: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftShoulderIndex].y) >= 0.05f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.progress = 0.5f; } else if (jointsTracked[leftHandIndex] && jointsTracked[rightShoulderIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightShoulderIndex].y) >= 0.05f) { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = gestureData.joint == rightHandIndex ? jointsTracked[rightHandIndex] && jointsTracked[leftElbowIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftElbowIndex].y) < -0.15f && Mathf.Abs(jointsPos[rightHandIndex].x - gestureData.jointPos.x) <= 0.15f : jointsTracked[leftHandIndex] && jointsTracked[rightElbowIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightElbowIndex].y) < -0.15f && Mathf.Abs(jointsPos[leftHandIndex].x - gestureData.jointPos.x) <= 0.15f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for ZoomIn case GestureType.ZoomIn: Vector3 vectorZoomOut = (Vector3)jointsPos[rightHandIndex] - jointsPos[leftHandIndex]; float distZoomOut = vectorZoomOut.magnitude; switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[leftHandIndex] && jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[leftHandIndex].y >= gestureBottom && jointsPos[leftHandIndex].y <= gestureTop && jointsPos[rightHandIndex].y >= gestureBottom && jointsPos[rightHandIndex].y <= gestureTop && distZoomOut < 0.3f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.tagVector = Vector3.right; gestureData.tagFloat = 0f; gestureData.progress = 0.3f; } break; case 1: // gesture phase 2 = zooming if ((timestamp - gestureData.timestamp) < 1.0f) { float angleZoomOut = Vector3.Angle(gestureData.tagVector, vectorZoomOut) * Mathf.Sign(vectorZoomOut.y - gestureData.tagVector.y); bool isInPose = jointsTracked[leftHandIndex] && jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[leftHandIndex].y >= gestureBottom && jointsPos[leftHandIndex].y <= gestureTop && jointsPos[rightHandIndex].y >= gestureBottom && jointsPos[rightHandIndex].y <= gestureTop && distZoomOut < 1.5f && Mathf.Abs(angleZoomOut) < 20f; if (isInPose) { SetZoomFactor(userId, ref gestureData, 1.0f, ref jointsPos, ref jointsTracked); gestureData.timestamp = timestamp; gestureData.progress = 0.7f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for ZoomOut case GestureType.ZoomOut: Vector3 vectorZoomIn = (Vector3)jointsPos[rightHandIndex] - jointsPos[leftHandIndex]; float distZoomIn = vectorZoomIn.magnitude; switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[leftHandIndex] && jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[leftHandIndex].y >= gestureBottom && jointsPos[leftHandIndex].y <= gestureTop && jointsPos[rightHandIndex].y >= gestureBottom && jointsPos[rightHandIndex].y <= gestureTop && distZoomIn >= 0.7f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.tagVector = Vector3.right; gestureData.tagFloat = distZoomIn; gestureData.progress = 0.3f; } break; case 1: // gesture phase 2 = zooming if ((timestamp - gestureData.timestamp) < 1.0f) { float angleZoomIn = Vector3.Angle(gestureData.tagVector, vectorZoomIn) * Mathf.Sign(vectorZoomIn.y - gestureData.tagVector.y); bool isInPose = jointsTracked[leftHandIndex] && jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[leftHandIndex].y >= gestureBottom && jointsPos[leftHandIndex].y <= gestureTop && jointsPos[rightHandIndex].y >= gestureBottom && jointsPos[rightHandIndex].y <= gestureTop && distZoomIn >= 0.2f && Mathf.Abs(angleZoomIn) < 20f; if (isInPose) { SetZoomFactor(userId, ref gestureData, 0.0f, ref jointsPos, ref jointsTracked); gestureData.timestamp = timestamp; gestureData.progress = 0.7f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for Wheel case GestureType.Wheel: Vector3 vectorWheel = (Vector3)jointsPos[rightHandIndex] - jointsPos[leftHandIndex]; float distWheel = vectorWheel.magnitude; // Debug.Log(string.Format("{0}. Dist: {1:F1}, Tag: {2:F1}, Diff: {3:F1}", gestureData.state, // distWheel, gestureData.tagFloat, Mathf.Abs(distWheel - gestureData.tagFloat))); switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[leftHandIndex] && jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[leftHandIndex].y >= gestureBottom && jointsPos[leftHandIndex].y <= gestureTop && jointsPos[rightHandIndex].y >= gestureBottom && jointsPos[rightHandIndex].y <= gestureTop && distWheel >= 0.3f && distWheel < 0.7f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.tagVector = Vector3.right; gestureData.tagFloat = distWheel; gestureData.progress = 0.3f; } break; case 1: // gesture phase 2 = rotating if ((timestamp - gestureData.timestamp) < 0.5f) { float angle = Vector3.Angle(gestureData.tagVector, vectorWheel) * Mathf.Sign(vectorWheel.y - gestureData.tagVector.y); bool isInPose = jointsTracked[leftHandIndex] && jointsTracked[rightHandIndex] && jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[rightHipIndex] && jointsPos[leftHandIndex].y >= gestureBottom && jointsPos[leftHandIndex].y <= gestureTop && jointsPos[rightHandIndex].y >= gestureBottom && jointsPos[rightHandIndex].y <= gestureTop && distWheel >= 0.3f && distWheel < 0.7f && Mathf.Abs(distWheel - gestureData.tagFloat) < 0.1f; if (isInPose) { //SetWheelRotation(userId, ref gestureData, gestureData.tagVector, vectorWheel); gestureData.screenPos.z = angle; // wheel angle gestureData.timestamp = timestamp; gestureData.tagFloat = distWheel; gestureData.progress = 0.7f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for Jump case GestureType.Jump: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[hipCenterIndex] && (jointsPos[hipCenterIndex].y > 0.6f) && (jointsPos[hipCenterIndex].y < 1.2f)) { SetGestureJoint(ref gestureData, timestamp, hipCenterIndex, jointsPos[hipCenterIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = jointsTracked[hipCenterIndex] && (jointsPos[hipCenterIndex].y - gestureData.jointPos.y) > 0.15f && Mathf.Abs(jointsPos[hipCenterIndex].x - gestureData.jointPos.x) < 0.2f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for Squat case GestureType.Squat: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[hipCenterIndex] && (jointsPos[hipCenterIndex].y <= 0.7f)) { SetGestureJoint(ref gestureData, timestamp, hipCenterIndex, jointsPos[hipCenterIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = jointsTracked[hipCenterIndex] && (jointsPos[hipCenterIndex].y - gestureData.jointPos.y) < -0.15f && Mathf.Abs(jointsPos[hipCenterIndex].x - gestureData.jointPos.x) < 0.2f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for Push case GestureType.Push: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[rightHandIndex] && jointsTracked[leftElbowIndex] && jointsTracked[rightShoulderIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftElbowIndex].y) > -0.1f && Mathf.Abs(jointsPos[rightHandIndex].x - jointsPos[rightShoulderIndex].x) < 0.2f && (jointsPos[rightHandIndex].z - jointsPos[leftElbowIndex].z) < -0.2f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.progress = 0.5f; } else if (jointsTracked[leftHandIndex] && jointsTracked[rightElbowIndex] && jointsTracked[leftShoulderIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightElbowIndex].y) > -0.1f && Mathf.Abs(jointsPos[leftHandIndex].x - jointsPos[leftShoulderIndex].x) < 0.2f && (jointsPos[leftHandIndex].z - jointsPos[rightElbowIndex].z) < -0.2f) { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = gestureData.joint == rightHandIndex ? jointsTracked[rightHandIndex] && jointsTracked[leftElbowIndex] && jointsTracked[rightShoulderIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftElbowIndex].y) > -0.1f && Mathf.Abs(jointsPos[rightHandIndex].x - gestureData.jointPos.x) < 0.2f && (jointsPos[rightHandIndex].z - gestureData.jointPos.z) < -0.2f : jointsTracked[leftHandIndex] && jointsTracked[rightElbowIndex] && jointsTracked[leftShoulderIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightElbowIndex].y) > -0.1f && Mathf.Abs(jointsPos[leftHandIndex].x - gestureData.jointPos.x) < 0.2f && (jointsPos[leftHandIndex].z - gestureData.jointPos.z) < -0.2f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for Pull case GestureType.Pull: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[rightHandIndex] && jointsTracked[leftElbowIndex] && jointsTracked[rightShoulderIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftElbowIndex].y) > -0.1f && Mathf.Abs(jointsPos[rightHandIndex].x - jointsPos[rightShoulderIndex].x) < 0.2f && (jointsPos[rightHandIndex].z - jointsPos[leftElbowIndex].z) < -0.3f) { SetGestureJoint(ref gestureData, timestamp, rightHandIndex, jointsPos[rightHandIndex]); gestureData.progress = 0.5f; } else if (jointsTracked[leftHandIndex] && jointsTracked[rightElbowIndex] && jointsTracked[leftShoulderIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightElbowIndex].y) > -0.1f && Mathf.Abs(jointsPos[leftHandIndex].x - jointsPos[leftShoulderIndex].x) < 0.2f && (jointsPos[leftHandIndex].z - jointsPos[rightElbowIndex].z) < -0.3f) { SetGestureJoint(ref gestureData, timestamp, leftHandIndex, jointsPos[leftHandIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = gestureData.joint == rightHandIndex ? jointsTracked[rightHandIndex] && jointsTracked[leftElbowIndex] && jointsTracked[rightShoulderIndex] && (jointsPos[rightHandIndex].y - jointsPos[leftElbowIndex].y) > -0.1f && Mathf.Abs(jointsPos[rightHandIndex].x - gestureData.jointPos.x) < 0.2f && (jointsPos[rightHandIndex].z - gestureData.jointPos.z) > 0.25f : jointsTracked[leftHandIndex] && jointsTracked[rightElbowIndex] && jointsTracked[leftShoulderIndex] && (jointsPos[leftHandIndex].y - jointsPos[rightElbowIndex].y) > -0.1f && Mathf.Abs(jointsPos[leftHandIndex].x - gestureData.jointPos.x) < 0.2f && (jointsPos[leftHandIndex].z - gestureData.jointPos.z) > 0.25f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for ShoulderLeftFron case GestureType.ShoulderLeftFront: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && (jointsPos[rightShoulderIndex].z - jointsPos[leftHipIndex].z) < 0f && (jointsPos[rightShoulderIndex].z - jointsPos[leftShoulderIndex].z) > -0.15f) { SetGestureJoint(ref gestureData, timestamp, rightShoulderIndex, jointsPos[rightShoulderIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[leftHipIndex] && (jointsPos[rightShoulderIndex].z - jointsPos[leftShoulderIndex].z) < -0.2f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for ShoulderRightFront case GestureType.ShoulderRightFront: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[rightHipIndex] && (jointsPos[leftShoulderIndex].z - jointsPos[rightHipIndex].z) < 0f && (jointsPos[leftShoulderIndex].z - jointsPos[rightShoulderIndex].z) > -0.15f) { SetGestureJoint(ref gestureData, timestamp, leftShoulderIndex, jointsPos[leftShoulderIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[rightHipIndex] && (jointsPos[leftShoulderIndex].z - jointsPos[rightShoulderIndex].z) < -0.2f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for LeanLeft case GestureType.LeanLeft: switch (gestureData.state) { case 0: // gesture detection - phase 1 (right shoulder is left of the right hip, means leaning left) if (jointsTracked[rightShoulderIndex] && jointsTracked[rightHipIndex] && jointsTracked[neckIndex] && (jointsPos[rightShoulderIndex].x - jointsPos[rightHipIndex].x) < 0f) { SetGestureJoint(ref gestureData, timestamp, rightShoulderIndex, jointsPos[rightShoulderIndex]); gestureData.progress = 0.3f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 0.5f) { // check if right shoulder is still left of the right hip (leaning left) bool isInPose = jointsTracked[rightShoulderIndex] && jointsTracked[rightHipIndex] && jointsTracked[neckIndex] && (jointsPos[rightShoulderIndex].x - jointsPos[rightHipIndex].x) < 0f; if (isInPose) { // calculate lean angle Vector3 vSpineLL = jointsPos[neckIndex] - jointsPos[hipCenterIndex]; gestureData.screenPos.z = Vector3.Angle(Vector3.up, vSpineLL); gestureData.timestamp = timestamp; gestureData.progress = 0.7f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for LeanRight case GestureType.LeanRight: switch (gestureData.state) { case 0: // gesture detection - phase 1 (left shoulder is right of the left hip, means leaning right) if (jointsTracked[leftShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[neckIndex] && (jointsPos[leftShoulderIndex].x - jointsPos[leftHipIndex].x) > 0f) { SetGestureJoint(ref gestureData, timestamp, leftShoulderIndex, jointsPos[leftShoulderIndex]); gestureData.progress = 0.3f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 0.5f) { // check if left shoulder is still right of the left hip (leaning right) bool isInPose = jointsTracked[leftShoulderIndex] && jointsTracked[leftHipIndex] && jointsTracked[neckIndex] && (jointsPos[leftShoulderIndex].x - jointsPos[leftHipIndex].x) > 0f; if (isInPose) { // calculate lean angle Vector3 vSpineLR = jointsPos[neckIndex] - jointsPos[hipCenterIndex]; gestureData.screenPos.z = Vector3.Angle(Vector3.up, vSpineLR); gestureData.timestamp = timestamp; gestureData.progress = 0.7f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for LeanForward case GestureType.LeanForward: switch (gestureData.state) { case 0: // gesture detection - phase 1 (shoulder center in front of hip center, means leaning forward) if (jointsTracked[neckIndex] && jointsTracked[hipCenterIndex] && (jointsPos[neckIndex].z - jointsPos[hipCenterIndex].z) < -0.1f) { SetGestureJoint(ref gestureData, timestamp, neckIndex, jointsPos[neckIndex]); gestureData.progress = 0.3f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 0.5f) { // check if shoulder center is still in front of the hip center (leaning forward) bool isInPose = jointsTracked[neckIndex] && jointsTracked[hipCenterIndex] && (jointsPos[neckIndex].z - jointsPos[leftHipIndex].z) < -0.1f; if (isInPose) { // calculate lean angle Vector3 vSpineLL = jointsPos[neckIndex] - jointsPos[hipCenterIndex]; gestureData.screenPos.z = Vector3.Angle(Vector3.up, vSpineLL); gestureData.timestamp = timestamp; gestureData.progress = 0.7f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for LeanBack case GestureType.LeanBack: switch (gestureData.state) { case 0: // gesture detection - phase 1 (shoulder center behind hip center, means leaning back) if (jointsTracked[neckIndex] && jointsTracked[hipCenterIndex] && (jointsPos[neckIndex].z - jointsPos[hipCenterIndex].z) > 0.1f) { SetGestureJoint(ref gestureData, timestamp, neckIndex, jointsPos[neckIndex]); gestureData.progress = 0.3f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 0.5f) { // check if shoulder center is still behind of the hip center (leaning back) bool isInPose = jointsTracked[neckIndex] && jointsTracked[hipCenterIndex] && (jointsPos[neckIndex].z - jointsPos[leftHipIndex].z) > 0.1f; if (isInPose) { // calculate lean angle Vector3 vSpineLR = jointsPos[neckIndex] - jointsPos[hipCenterIndex]; gestureData.screenPos.z = Vector3.Angle(Vector3.up, vSpineLR); gestureData.timestamp = timestamp; gestureData.progress = 0.7f; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for KickLeft case GestureType.KickLeft: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[leftAnkleIndex] && jointsTracked[rightAnkleIndex] && jointsTracked[leftHipIndex] && (jointsPos[leftAnkleIndex].z - jointsPos[leftHipIndex].z) < 0f && (jointsPos[leftAnkleIndex].z - jointsPos[rightAnkleIndex].z) > -0.2f) { SetGestureJoint(ref gestureData, timestamp, leftAnkleIndex, jointsPos[leftAnkleIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = jointsTracked[leftAnkleIndex] && jointsTracked[rightAnkleIndex] && jointsTracked[leftHipIndex] && (jointsPos[leftAnkleIndex].z - jointsPos[rightAnkleIndex].z) < -0.4f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // check for KickRight case GestureType.KickRight: switch (gestureData.state) { case 0: // gesture detection - phase 1 if (jointsTracked[leftAnkleIndex] && jointsTracked[rightAnkleIndex] && jointsTracked[rightHipIndex] && (jointsPos[rightAnkleIndex].z - jointsPos[rightHipIndex].z) < 0f && (jointsPos[rightAnkleIndex].z - jointsPos[leftAnkleIndex].z) > -0.2f) { SetGestureJoint(ref gestureData, timestamp, rightAnkleIndex, jointsPos[rightAnkleIndex]); gestureData.progress = 0.5f; } break; case 1: // gesture phase 2 = complete if ((timestamp - gestureData.timestamp) < 1.5f) { bool isInPose = jointsTracked[leftAnkleIndex] && jointsTracked[rightAnkleIndex] && jointsTracked[rightHipIndex] && (jointsPos[rightAnkleIndex].z - jointsPos[leftAnkleIndex].z) < -0.4f; if (isInPose) { Vector3 jointPos = jointsPos[gestureData.joint]; CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f); } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; case GestureType.Run: switch (gestureData.state) { case 0: // gesture detection - phase 1 // check if the left knee is up if (jointsTracked[leftKneeIndex] && jointsTracked[rightKneeIndex] && (jointsPos[leftKneeIndex].y - jointsPos[rightKneeIndex].y) > 0.1f) { SetGestureJoint(ref gestureData, timestamp, leftKneeIndex, jointsPos[leftKneeIndex]); gestureData.progress = 0.3f; } break; case 1: // gesture complete if ((timestamp - gestureData.timestamp) < 1.0f) { // check if the right knee is up bool isInPose = jointsTracked[rightKneeIndex] && jointsTracked[leftKneeIndex] && (jointsPos[rightKneeIndex].y - jointsPos[leftKneeIndex].y) > 0.1f; if (isInPose) { // go to state 2 gestureData.timestamp = timestamp; gestureData.progress = 0.7f; gestureData.state = 2; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; case 2: // gesture complete if ((timestamp - gestureData.timestamp) < 1.0f) { // check if the left knee is up again bool isInPose = jointsTracked[leftKneeIndex] && jointsTracked[rightKneeIndex] && (jointsPos[leftKneeIndex].y - jointsPos[rightKneeIndex].y) > 0.1f; if (isInPose) { // go back to state 1 gestureData.timestamp = timestamp; gestureData.progress = 0.8f; gestureData.state = 1; } } else { // cancel the gesture SetGestureCancelled(ref gestureData); } break; } break; // here come more gesture-cases } } } }