KinectManager

Autor: felipe 80 visualizações

KinectManager

Classe desenvolvida pela Microsft com diversas funcionalidades para explorar os recursos do Kinect.

				
					using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using System;
using System.Collections.Generic;
using WindowsInput;

public class KinectManager : MonoBehaviour
{
    public InputSimulator IS;

    public AvatarController avatarController;

    public KinectWrapper.NuiSkeletonPositionIndex rightKnee = KinectWrapper.NuiSkeletonPositionIndex.KneeRight;
    public KinectWrapper.NuiSkeletonPositionIndex leftKnee = KinectWrapper.NuiSkeletonPositionIndex.KneeLeft;

    public KinectWrapper.NuiSkeletonPositionIndex rightShoulder = KinectWrapper.NuiSkeletonPositionIndex.ShoulderRight;
    public KinectWrapper.NuiSkeletonPositionIndex leftShoulder = KinectWrapper.NuiSkeletonPositionIndex.ShoulderLeft;

    // Joint position at the moment, in Kinect coordinates
    public enum Smoothing : int
    {
        None,
        Default,
        Medium,
        Aggressive
    }

    // Public Bool to determine how many players there are. Default of one user.
    public bool TwoUsers = false;

    // Public Bool to determine if the sensor is used in near mode.
    //public bool NearMode = false;

    // Public Bool to determine whether to receive and compute the user map
    public bool ComputeUserMap = false;

    // Public Bool to determine whether to receive and compute the color map
    public bool ComputeColorMap = false;

    // Public Bool to determine whether to display user map on the GUI
    public bool DisplayUserMap = false;

    // Public Bool to determine whether to display color map on the GUI
    public bool DisplayColorMap = false;

    // Public Bool to determine whether to display the skeleton lines on user map
    public bool DisplaySkeletonLines = false;

    // Public Float to specify the image width used by depth and color maps, as % of the camera width. the height is calculated depending on the width.
    // if percent is zero, it is calculated internally to match the selected width and height of the depth image
    public float DisplayMapsWidthPercent = 20f;

    // How high off the ground is the sensor (in meters).
    public float SensorHeight = 1.0f;

    // Kinect elevation angle (in degrees)
    public int SensorAngle = 0;

    // Minimum user distance in order to process skeleton data
    public float MinUserDistance = 1.0f;

    // Maximum user distance, if any. 0 means no max-distance limitation
    public float MaxUserDistance = 0f;

    // Public Bool to determine whether to detect only the closest user or not
    public bool DetectClosestUser = true;

    // Public Bool to determine whether to use only the tracked joints (and ignore the inferred ones)
    public bool IgnoreInferredJoints = true;

    // Selection of smoothing parameters
    public Smoothing smoothing = Smoothing.Default;

    // Public Bool to determine the use of additional filters
    public bool UseBoneOrientationsFilter = false;
    public bool UseClippedLegsFilter = false;
    public bool UseBoneOrientationsConstraint = true;
    public bool UseSelfIntersectionConstraint = false;

    // Lists of GameObjects that will be controlled by which player.
    public List<GameObject> Player1Avatars;
    public List<GameObject> Player2Avatars;

    // Calibration poses for each player, if needed
    public KinectGestures.Gestures Player1CalibrationPose;
    public KinectGestures.Gestures Player2CalibrationPose;

    // List of Gestures to detect for each player
    public List<KinectGestures.Gestures> Player1Gestures;
    public List<KinectGestures.Gestures> Player2Gestures;

    // Minimum time between gesture detections
    public float MinTimeBetweenGestures = 0.7f;

    // List of Gesture Listeners. They must implement KinectGestures.GestureListenerInterface
    public List<MonoBehaviour> GestureListeners;

    // GUI Text to show messages.
    public Text CalibrationText;

    // GUI Texture to display the hand cursor for Player1
    public GameObject HandCursor1;

    // GUI Texture to display the hand cursor for Player1
    public GameObject HandCursor2;

    // Bool to specify whether Left/Right-hand-cursor and the Click-gesture control the mouse cursor and click
    public bool ControlMouseCursor = false;

    // GUI Text to show gesture debug message.
    public Text GesturesDebugText;

    // Game Object that displays the Recording icon
    public GameObject recordingDisplay;

    // Game Object that contains the exit button
    public GameObject exitButton;

    // Bool to keep track of whether Kinect has been initialized
    private bool KinectInitialized = false;

    // Bools to keep track of who is currently calibrated.
    public static bool Player1Calibrated = false;
    private bool Player2Calibrated = false;

    private bool AllPlayersCalibrated = false;

    // Values to track which ID (assigned by the Kinect) is player 1 and player 2.
    private static uint Player1ID;
    private static uint Player2ID;

    private int Player1Index;
    private int Player2Index;

    // Lists of AvatarControllers that will let the models get updated.
    private List<AvatarController> Player1Controllers;
    private List<AvatarController> Player2Controllers;

    // User Map vars.
    private Texture2D usersLblTex;
    private Color32[] usersMapColors;
    private ushort[] usersPrevState;
    private Rect usersMapRect;
    private int usersMapSize;

    private Texture2D usersClrTex;

    // Color[] usersClrColors;
    private Rect usersClrRect;

    // short[] usersLabelMap;
    private ushort[] usersDepthMap;
    private float[] usersHistogramMap;

    // List of all users
    private List<uint> allUsers;

    // Image stream handles for the kinect
    private IntPtr colorStreamHandle;
    private IntPtr depthStreamHandle;

    // Color image data, if used
    private Color32[] colorImage;
    private byte[] usersColorMap;

    // Skeleton related structures
    private static KinectWrapper.NuiSkeletonFrame skeletonFrame;
    private KinectWrapper.NuiTransformSmoothParameters smoothParameters;
    private static int player1Index;
    private static int player2Index;

    // Skeleton tracking states, positions and joints' orientations
    private Vector3 player1Pos, player2Pos;
    private Matrix4x4 player1Ori, player2Ori;
    private bool[] player1JointsTracked, player2JointsTracked;
    private bool[] player1PrevTracked, player2PrevTracked;
    private static Vector3[] player1JointsPos;
    private static Vector3[] player2JointsPos;
    private Matrix4x4[] player1JointsOri, player2JointsOri;
    private KinectWrapper.NuiSkeletonBoneOrientation[] jointOrientations;

    // Calibration gesture data for each player
    private KinectGestures.GestureData player1CalibrationData;
    private KinectGestures.GestureData player2CalibrationData;

    // Lists of gesture data, for each player
    private List<KinectGestures.GestureData> player1Gestures = new List<KinectGestures.GestureData>();
    private List<KinectGestures.GestureData> player2Gestures = new List<KinectGestures.GestureData>();

    // General gesture tracking time start
    private float[] gestureTrackingAtTime;

    // List of Gesture Listeners. They must implement KinectGestures.GestureListenerInterface
    public List<KinectGestures.GestureListenerInterface> gestureListeners;

    private Matrix4x4 kinectToWorld, flipMatrix;
    private static KinectManager instance;

    // Timer for controlling Filter Lerp blends.
    private float lastNuiTime;

    // Filters
    private TrackingStateFilter[] trackingStateFilter;
    private BoneOrientationsFilter[] boneOrientationFilter;
    private ClippedLegsFilter[] clippedLegsFilter;
    private BoneOrientationsConstraint boneConstraintsFilter;
    private SelfIntersectionConstraint selfIntersectionConstraint;

    // UnityEvents
    public UnityEvent OnRecordingBegin;
    public UnityEvent OnRecordingFinish;

    void Start()
    {
        IS = new InputSimulator();
    }

    // Returns the single KinectManager instance
    public static KinectManager Instance
    {
        get { return instance; }
    }

    // Checks if Kinect is initialized and ready to use. If not, there was an error during Kinect-sensor initialization
    public static bool IsKinectInitialized()
    {
        return instance != null ? instance.KinectInitialized : false;
    }

    // Checks if Kinect is initialized and ready to use. If not, there was an error during Kinect-sensor initialization
    public bool IsInitialized()
    {
        return KinectInitialized;
    }

    // This function is used internally by AvatarController
    public static bool IsCalibrationNeeded()
    {
        return false;
    }

    // Returns the raw depth/user data, if ComputeUserMap is true
    public ushort[] GetRawDepthMap()
    {
        return usersDepthMap;
    }

    // Returns the depth data for a specific pixel, if ComputeUserMap is true
    public ushort GetDepthForPixel(int x, int y)
    {
        int index = y * KinectWrapper.Constants.DepthImageWidth + x;

        if (index >= 0 && index < usersDepthMap.Length)
            return usersDepthMap[index];
        else
            return 0;
    }

    // Returns the depth map position for a 3d joint position
    public Vector2 GetDepthMapPosForJointPos(Vector3 posJoint)
    {
        Vector3 vDepthPos = KinectWrapper.MapSkeletonPointToDepthPoint(posJoint);
        Vector2 vMapPos = new Vector2(vDepthPos.x, vDepthPos.y);

        return vMapPos;
    }

    // Returns the color map position for a depth 2d position
    public Vector2 GetColorMapPosForDepthPos(Vector2 posDepth)
    {
        int cx, cy;

        KinectWrapper.NuiImageViewArea pcViewArea = new KinectWrapper.NuiImageViewArea
        {
            eDigitalZoom = 0,
            lCenterX = 0,
            lCenterY = 0
        };

        KinectWrapper.NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution(
            KinectWrapper.Constants.ColorImageResolution,
            KinectWrapper.Constants.DepthImageResolution,
            ref pcViewArea,
            (int)posDepth.x, (int)posDepth.y, GetDepthForPixel((int)posDepth.x, (int)posDepth.y),
            out cx, out cy);

        return new Vector2(cx, cy);
    }

    // Returns the depth image/users histogram texture,if ComputeUserMap is true
    public Texture2D GetUsersLblTex()
    {
        return usersLblTex;
    }

    // Returns the color image texture,if ComputeColorMap is true
    public Texture2D GetUsersClrTex()
    {
        return usersClrTex;
    }

    // Returns true if at least one user is currently detected by the sensor
    public bool IsUserDetected()
    {
        return KinectInitialized && (allUsers.Count > 0);
    }

    // Returns the UserID of Player1, or 0 if no Player1 is detected
    public static uint GetPlayer1ID()
    {
        return Player1ID;
    }

    // Returns the UserID of Player2, or 0 if no Player2 is detected
    public uint GetPlayer2ID()
    {
        return Player2ID;
    }

    // Returns the index of Player1, or 0 if no Player2 is detected
    public int GetPlayer1Index()
    {
        return Player1Index;
    }

    // Returns the index of Player2, or 0 if no Player2 is detected
    public int GetPlayer2Index()
    {
        return Player2Index;
    }

    // Returns true if the User is calibrated and ready to use
    public bool IsPlayerCalibrated(uint UserId)
    {
        if (UserId == Player1ID)
            return Player1Calibrated;
        else if (UserId == Player2ID)
            return Player2Calibrated;

        return false;
    }

    // Returns the raw unmodified joint position, as returned by the Kinect sensor
    public static Vector3 GetRawSkeletonJointPos(uint UserId, int joint)
    {
        if (UserId == Player1ID)
            return joint >= 0 && joint < player1JointsPos.Length
                ? (Vector3)skeletonFrame.SkeletonData[player1Index].SkeletonPositions[joint]
                : Vector3.zero;
        else if (UserId == Player2ID)
            return joint >= 0 && joint < player2JointsPos.Length
                ? (Vector3)skeletonFrame.SkeletonData[player2Index].SkeletonPositions[joint]
                : Vector3.zero;

        return Vector3.zero;
    }

    // Returns the User position, relative to the Kinect-sensor, in meters
    public Vector3 GetUserPosition(uint UserId)
    {
        if (UserId == Player1ID)
            return player1Pos;
        else if (UserId == Player2ID)
            return player2Pos;

        return Vector3.zero;
    }

    // Returns the User rotation, relative to the Kinect-sensor
    public Quaternion GetUserOrientation(uint UserId, bool flip)
    {
        if (UserId == Player1ID && player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.HipCenter])
            return ConvertMatrixToQuat(player1Ori, (int)KinectWrapper.NuiSkeletonPositionIndex.HipCenter, flip);
        else if (UserId == Player2ID && player2JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.HipCenter])
            return ConvertMatrixToQuat(player2Ori, (int)KinectWrapper.NuiSkeletonPositionIndex.HipCenter, flip);

        return Quaternion.identity;
    }

    // Returns true if the given joint of the specified user is being tracked
    public bool IsJointTracked(uint UserId, int joint)
    {
        if (UserId == Player1ID)
            return joint >= 0 && joint < player1JointsTracked.Length ? player1JointsTracked[joint] : false;
        else if (UserId == Player2ID)
            return joint >= 0 && joint < player2JointsTracked.Length ? player2JointsTracked[joint] : false;

        return false;
    }

    // Returns the joint position of the specified user, relative to the Kinect-sensor, in meters
    public Vector3 GetJointPosition(uint UserId, int joint)
    {
        if (UserId == Player1ID)
            return joint >= 0 && joint < player1JointsPos.Length ? player1JointsPos[joint] : Vector3.zero;
        else if (UserId == Player2ID)
            return joint >= 0 && joint < player2JointsPos.Length ? player2JointsPos[joint] : Vector3.zero;

        return Vector3.zero;
    }

    // Returns the local joint position of the specified user, relative to the parent joint, in meters
    public Vector3 GetJointLocalPosition(uint UserId, int joint)
    {
        int parent = KinectWrapper.GetSkeletonJointParent(joint);

        if (UserId == Player1ID)
            return joint >= 0 && joint < player1JointsPos.Length
                ? (player1JointsPos[joint] - player1JointsPos[parent])
                : Vector3.zero;
        else if (UserId == Player2ID)
            return joint >= 0 && joint < player2JointsPos.Length
                ? (player2JointsPos[joint] - player2JointsPos[parent])
                : Vector3.zero;

        return Vector3.zero;
    }

    // Returns the joint rotation of the specified user, relative to the Kinect-sensor
    public Quaternion GetJointOrientation(uint UserId, int joint, bool flip)
    {
        if (UserId == Player1ID)
        {
            if (joint >= 0 && joint < player1JointsOri.Length && player1JointsTracked[joint])
                return ConvertMatrixToQuat(player1JointsOri[joint], joint, flip);
        }
        else if (UserId == Player2ID)
        {
            if (joint >= 0 && joint < player2JointsOri.Length && player2JointsTracked[joint])
                return ConvertMatrixToQuat(player2JointsOri[joint], joint, flip);
        }

        return Quaternion.identity;
    }

    // Returns the joint rotation of the specified user, relative to the parent joint
    public Quaternion GetJointLocalOrientation(uint UserId, int joint, bool flip)
    {
        int parent = KinectWrapper.GetSkeletonJointParent(joint);

        if (UserId == Player1ID)
        {
            if (joint >= 0 && joint < player1JointsOri.Length && player1JointsTracked[joint])
            {
                Matrix4x4 localMat = (player1JointsOri[parent].inverse * player1JointsOri[joint]);
                return Quaternion.LookRotation(localMat.GetColumn(2), localMat.GetColumn(1));
            }
        }
        else if (UserId == Player2ID)
        {
            if (joint >= 0 && joint < player2JointsOri.Length && player2JointsTracked[joint])
            {
                Matrix4x4 localMat = (player2JointsOri[parent].inverse * player2JointsOri[joint]);
                return Quaternion.LookRotation(localMat.GetColumn(2), localMat.GetColumn(1));
            }
        }

        return Quaternion.identity;
    }

    // Returns the direction between baseJoint and nextJoint, for the specified user
    public Vector3 GetDirectionBetweenJoints(uint UserId, int baseJoint, int nextJoint, bool flipX, bool flipZ)
    {
        Vector3 jointDir = Vector3.zero;

        if (UserId == Player1ID)
        {
            if (baseJoint >= 0 && baseJoint < player1JointsPos.Length && player1JointsTracked[baseJoint] &&
                nextJoint >= 0 && nextJoint < player1JointsPos.Length && player1JointsTracked[nextJoint])
            {
                jointDir = player1JointsPos[nextJoint] - player1JointsPos[baseJoint];
            }
        }
        else if (UserId == Player2ID)
        {
            if (baseJoint >= 0 && baseJoint < player2JointsPos.Length && player2JointsTracked[baseJoint] &&
                nextJoint >= 0 && nextJoint < player2JointsPos.Length && player2JointsTracked[nextJoint])
            {
                jointDir = player2JointsPos[nextJoint] - player2JointsPos[baseJoint];
            }
        }

        if (jointDir != Vector3.zero)
        {
            if (flipX)
                jointDir.x = -jointDir.x;

            if (flipZ)
                jointDir.z = -jointDir.z;
        }

        return jointDir;
    }

    // Adds a gesture to the list of detected gestures for the specified user
    public void DetectGesture(uint UserId, KinectGestures.Gestures gesture)
    {
        int index = GetGestureIndex(UserId, gesture);
        if (index >= 0)
            DeleteGesture(UserId, gesture);

        KinectGestures.GestureData gestureData = new KinectGestures.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<KinectGestures.Gestures>();
        switch (gesture)
        {
            case KinectGestures.Gestures.ZoomIn:
                gestureData.checkForGestures.Add(KinectGestures.Gestures.ZoomOut);
                gestureData.checkForGestures.Add(KinectGestures.Gestures.Wheel);
                break;

            case KinectGestures.Gestures.ZoomOut:
                gestureData.checkForGestures.Add(KinectGestures.Gestures.ZoomIn);
                gestureData.checkForGestures.Add(KinectGestures.Gestures.Wheel);
                break;

            case KinectGestures.Gestures.Wheel:
                gestureData.checkForGestures.Add(KinectGestures.Gestures.ZoomIn);
                gestureData.checkForGestures.Add(KinectGestures.Gestures.ZoomOut);
                break;
        }

        if (UserId == Player1ID)
            player1Gestures.Add(gestureData);
        else if (UserId == Player2ID)
            player2Gestures.Add(gestureData);
    }

    // Resets the gesture-data state for the given gesture of the specified user
    public bool ResetGesture(uint UserId, KinectGestures.Gestures gesture)
    {
        int index = GetGestureIndex(UserId, gesture);
        if (index < 0)
            return false;

        KinectGestures.GestureData
            gestureData = (UserId == Player1ID) ? player1Gestures[index] : player2Gestures[index];

        gestureData.state = 0;
        gestureData.joint = 0;
        gestureData.progress = 0f;
        gestureData.complete = false;
        gestureData.cancelled = false;
        gestureData.startTrackingAtTime =
            Time.realtimeSinceStartup + KinectWrapper.Constants.MinTimeBetweenSameGestures;

        if (UserId == Player1ID)
            player1Gestures[index] = gestureData;
        else if (UserId == Player2ID)
            player2Gestures[index] = gestureData;

        return true;
    }

    // Resets the gesture-data states for all detected gestures of the specified user
    public void ResetPlayerGestures(uint UserId)
    {
        if (UserId == Player1ID)
        {
            int listSize = player1Gestures.Count;

            for (int i = 0; i < listSize; i++)
            {
                ResetGesture(UserId, player1Gestures[i].gesture);
            }
        }
        else if (UserId == Player2ID)
        {
            int listSize = player2Gestures.Count;

            for (int i = 0; i < listSize; i++)
            {
                ResetGesture(UserId, player2Gestures[i].gesture);
            }
        }
    }

    // Deletes the given gesture from the list of detected gestures for the specified user
    public bool DeleteGesture(uint UserId, KinectGestures.Gestures gesture)
    {
        int index = GetGestureIndex(UserId, gesture);
        if (index < 0)
            return false;

        if (UserId == Player1ID)
            player1Gestures.RemoveAt(index);
        else if (UserId == Player2ID)
            player2Gestures.RemoveAt(index);

        return true;
    }

    // Clears detected gestures list for the specified user
    public void ClearGestures(uint UserId)
    {
        if (UserId == Player1ID)
        {
            player1Gestures.Clear();
        }
        else if (UserId == Player2ID)
        {
            player2Gestures.Clear();
        }
    }

    // Returns the count of detected gestures in the list of detected gestures for the specified user
    public int GetGesturesCount(uint UserId)
    {
        if (UserId == Player1ID)
            return player1Gestures.Count;
        else if (UserId == Player2ID)
            return player2Gestures.Count;

        return 0;
    }

    // Returns the list of detected gestures for the specified user
    public List<KinectGestures.Gestures> GetGesturesList(uint UserId)
    {
        List<KinectGestures.Gestures> list = new List<KinectGestures.Gestures>();

        if (UserId == Player1ID)
        {
            foreach (KinectGestures.GestureData data in player1Gestures)
                list.Add(data.gesture);
        }
        else if (UserId == Player2ID)
        {
            foreach (KinectGestures.GestureData data in player1Gestures)
                list.Add(data.gesture);
        }

        return list;
    }

    // Returns true, if the given gesture is in the list of detected gestures for the specified user
    public bool IsGestureDetected(uint UserId, KinectGestures.Gestures gesture)
    {
        int index = GetGestureIndex(UserId, gesture);
        return index >= 0;
    }

    // Returns true, if the given gesture for the specified user is complete
    public bool IsGestureComplete(uint UserId, KinectGestures.Gestures gesture, bool bResetOnComplete)
    {
        int index = GetGestureIndex(UserId, gesture);

        if (index >= 0)
        {
            if (UserId == Player1ID)
            {
                KinectGestures.GestureData gestureData = player1Gestures[index];

                if (bResetOnComplete && gestureData.complete)
                {
                    ResetPlayerGestures(UserId);
                    return true;
                }

                return gestureData.complete;
            }
            else if (UserId == Player2ID)
            {
                KinectGestures.GestureData gestureData = player2Gestures[index];

                if (bResetOnComplete && gestureData.complete)
                {
                    ResetPlayerGestures(UserId);
                    return true;
                }

                return gestureData.complete;
            }
        }

        return false;
    }

    // Returns true, if the given gesture for the specified user is cancelled
    public bool IsGestureCancelled(uint UserId, KinectGestures.Gestures gesture)
    {
        int index = GetGestureIndex(UserId, gesture);

        if (index >= 0)
        {
            if (UserId == Player1ID)
            {
                KinectGestures.GestureData gestureData = player1Gestures[index];
                return gestureData.cancelled;
            }
            else if (UserId == Player2ID)
            {
                KinectGestures.GestureData gestureData = player2Gestures[index];
                return gestureData.cancelled;
            }
        }

        return false;
    }

    // Returns the progress in range [0, 1] of the given gesture for the specified user
    public float GetGestureProgress(uint UserId, KinectGestures.Gestures gesture)
    {
        int index = GetGestureIndex(UserId, gesture);

        if (index >= 0)
        {
            if (UserId == Player1ID)
            {
                KinectGestures.GestureData gestureData = player1Gestures[index];
                return gestureData.progress;
            }
            else if (UserId == Player2ID)
            {
                KinectGestures.GestureData gestureData = player2Gestures[index];
                return gestureData.progress;
            }
        }

        return 0f;
    }

    // Returns the current "screen position" of the given gesture for the specified user
    public Vector3 GetGestureScreenPos(uint UserId, KinectGestures.Gestures gesture)
    {
        int index = GetGestureIndex(UserId, gesture);

        if (index >= 0)
        {
            if (UserId == Player1ID)
            {
                KinectGestures.GestureData gestureData = player1Gestures[index];
                return gestureData.screenPos;
            }
            else if (UserId == Player2ID)
            {
                KinectGestures.GestureData gestureData = player2Gestures[index];
                return gestureData.screenPos;
            }
        }

        return Vector3.zero;
    }

    // Recreates and reinitializes the internal list of gesture listeners
    public void ResetGestureListeners()
    {
        // create the list of gesture listeners
        gestureListeners.Clear();

        foreach (MonoBehaviour script in GestureListeners)
        {
            if (script && (script is KinectGestures.GestureListenerInterface))
            {
                KinectGestures.GestureListenerInterface listener = (KinectGestures.GestureListenerInterface)script;
                gestureListeners.Add(listener);
            }
        }
    }

    // Recreates and reinitializes the lists of avatar controllers, after the list of avatars for player 1/2 was changed
    public void ResetAvatarControllers()
    {
        if (Player1Avatars.Count == 0 && Player2Avatars.Count == 0)
        {
            AvatarController[] avatars = FindObjectsOfType(typeof(AvatarController)) as AvatarController[];

            foreach (AvatarController avatar in avatars)
            {
                Player1Avatars.Add(avatar.gameObject);
            }
        }

        if (Player1Controllers != null)
        {
            Player1Controllers.Clear();

            foreach (GameObject avatar in Player1Avatars)
            {
                if (avatar != null && avatar.activeInHierarchy)
                {
                    AvatarController controller = avatar.GetComponent<AvatarController>();
                    controller.ResetToInitialPosition();
                    controller.Awake();

                    Player1Controllers.Add(controller);
                }
            }
        }

        if (Player2Controllers != null)
        {
            Player2Controllers.Clear();

            foreach (GameObject avatar in Player2Avatars)
            {
                if (avatar != null && avatar.activeInHierarchy)
                {
                    AvatarController controller = avatar.GetComponent<AvatarController>();
                    controller.ResetToInitialPosition();
                    controller.Awake();

                    Player2Controllers.Add(controller);
                }
            }
        }
    }

    // Removes the currently detected kinect users, allowing a new detection/calibration process to start
    public void ClearKinectUsers()
    {
        if (!KinectInitialized)
            return;

        // remove current users
        for (int i = allUsers.Count - 1; i >= 0; i--)
        {
            uint userId = allUsers[i];
            RemoveUser(userId);
        }

        ResetFilters();
    }

    // Clears Kinect buffers and resets the filters
    public void ResetFilters()
    {
        if (!KinectInitialized)
            return;

        // clear kinect vars
        player1Pos = Vector3.zero;
        player2Pos = Vector3.zero;
        player1Ori = Matrix4x4.identity;
        player2Ori = Matrix4x4.identity;

        int skeletonJointsCount = (int)KinectWrapper.NuiSkeletonPositionIndex.Count;
        for (int i = 0; i < skeletonJointsCount; i++)
        {
            player1JointsTracked[i] = false;
            player2JointsTracked[i] = false;
            player1PrevTracked[i] = false;
            player2PrevTracked[i] = false;
            player1JointsPos[i] = Vector3.zero;
            player2JointsPos[i] = Vector3.zero;
            player1JointsOri[i] = Matrix4x4.identity;
            player2JointsOri[i] = Matrix4x4.identity;
        }

        if (trackingStateFilter != null)
        {
            for (int i = 0; i < trackingStateFilter.Length; i++)
                if (trackingStateFilter[i] != null)
                    trackingStateFilter[i].Reset();
        }

        if (boneOrientationFilter != null)
        {
            for (int i = 0; i < boneOrientationFilter.Length; i++)
                if (boneOrientationFilter[i] != null)
                    boneOrientationFilter[i].Reset();
        }

        if (clippedLegsFilter != null)
        {
            for (int i = 0; i < clippedLegsFilter.Length; i++)
                if (clippedLegsFilter[i] != null)
                    clippedLegsFilter[i].Reset();
        }
    }


    //----------------------------------- end of public functions --------------------------------------//

    void Awake()
    {
        int hr = 0;
        try
        {
            hr = KinectWrapper.NuiInitialize(KinectWrapper.NuiInitializeFlags.UsesSkeleton |
                                             KinectWrapper.NuiInitializeFlags.UsesDepthAndPlayerIndex |
                                             (ComputeColorMap ? KinectWrapper.NuiInitializeFlags.UsesColor : 0));
            if (hr != 0)
            {
                throw new Exception("NuiInitialize Failed");
            }

            hr = KinectWrapper.NuiSkeletonTrackingEnable(IntPtr.Zero, 8); // 0, 12,8
            if (hr != 0)
            {
                throw new Exception("Cannot initialize Skeleton Data");
            }

            depthStreamHandle = IntPtr.Zero;
            if (ComputeUserMap)
            {
                hr = KinectWrapper.NuiImageStreamOpen(KinectWrapper.NuiImageType.DepthAndPlayerIndex,
                    KinectWrapper.Constants.DepthImageResolution, 0, 2, IntPtr.Zero, ref depthStreamHandle);
                if (hr != 0)
                {
                    throw new Exception("Cannot open depth stream");
                }
            }

            colorStreamHandle = IntPtr.Zero;
            if (ComputeColorMap)
            {
                hr = KinectWrapper.NuiImageStreamOpen(KinectWrapper.NuiImageType.Color,
                    KinectWrapper.Constants.ColorImageResolution, 0, 2, IntPtr.Zero, ref colorStreamHandle);
                if (hr != 0)
                {
                    throw new Exception("Cannot open color stream");
                }
            }

            // Set kinect elevation angle
            KinectWrapper.NuiCameraElevationSetAngle(SensorAngle);

            // Init skeleton structures
            skeletonFrame = new KinectWrapper.NuiSkeletonFrame()
            {
                SkeletonData = new KinectWrapper.NuiSkeletonData[KinectWrapper.Constants.NuiSkeletonCount]
            };

            // Values used to pass to smoothing function
            smoothParameters = new KinectWrapper.NuiTransformSmoothParameters();

            switch (smoothing)
            {
                case Smoothing.Default:
                    smoothParameters.fSmoothing = 0.5f;
                    smoothParameters.fCorrection = 0.5f;
                    smoothParameters.fPrediction = 0.5f;
                    smoothParameters.fJitterRadius = 0.05f;
                    smoothParameters.fMaxDeviationRadius = 0.04f;
                    break;
                case Smoothing.Medium:
                    smoothParameters.fSmoothing = 0.5f;
                    smoothParameters.fCorrection = 0.1f;
                    smoothParameters.fPrediction = 0.5f;
                    smoothParameters.fJitterRadius = 0.1f;
                    smoothParameters.fMaxDeviationRadius = 0.1f;
                    break;
                case Smoothing.Aggressive:
                    smoothParameters.fSmoothing = 0.7f;
                    smoothParameters.fCorrection = 0.3f;
                    smoothParameters.fPrediction = 1.0f;
                    smoothParameters.fJitterRadius = 1.0f;
                    smoothParameters.fMaxDeviationRadius = 1.0f;
                    break;
            }

            // init the tracking state filter
            trackingStateFilter = new TrackingStateFilter[KinectWrapper.Constants.NuiSkeletonMaxTracked];
            for (int i = 0; i < trackingStateFilter.Length; i++)
            {
                trackingStateFilter[i] = new TrackingStateFilter();
                trackingStateFilter[i].Init();
            }

            // init the bone orientation filter
            boneOrientationFilter = new BoneOrientationsFilter[KinectWrapper.Constants.NuiSkeletonMaxTracked];
            for (int i = 0; i < boneOrientationFilter.Length; i++)
            {
                boneOrientationFilter[i] = new BoneOrientationsFilter();
                boneOrientationFilter[i].Init();
            }

            // init the clipped legs filter
            clippedLegsFilter = new ClippedLegsFilter[KinectWrapper.Constants.NuiSkeletonMaxTracked];
            for (int i = 0; i < clippedLegsFilter.Length; i++)
            {
                clippedLegsFilter[i] = new ClippedLegsFilter();
            }

            // init the bone orientation constraints
            boneConstraintsFilter = new BoneOrientationsConstraint();
            boneConstraintsFilter.AddDefaultConstraints();
            // init the self intersection constraints
            selfIntersectionConstraint = new SelfIntersectionConstraint();

            // create arrays for joint positions and joint orientations
            int skeletonJointsCount = (int)KinectWrapper.NuiSkeletonPositionIndex.Count;

            player1JointsTracked = new bool[skeletonJointsCount];
            player2JointsTracked = new bool[skeletonJointsCount];
            player1PrevTracked = new bool[skeletonJointsCount];
            player2PrevTracked = new bool[skeletonJointsCount];

            player1JointsPos = new Vector3[skeletonJointsCount];
            player2JointsPos = new Vector3[skeletonJointsCount];

            player1JointsOri = new Matrix4x4[skeletonJointsCount];
            player2JointsOri = new Matrix4x4[skeletonJointsCount];

            gestureTrackingAtTime = new float[KinectWrapper.Constants.NuiSkeletonMaxTracked];

            //create the transform matrix that converts from kinect-space to world-space
            Quaternion quatTiltAngle = new Quaternion();
            quatTiltAngle.eulerAngles = new Vector3(-SensorAngle, 0.0f, 0.0f);

            kinectToWorld.SetTRS(new Vector3(0.0f, SensorHeight, 0.0f), quatTiltAngle, Vector3.one);
            flipMatrix = Matrix4x4.identity;
            flipMatrix[2, 2] = -1;

            instance = this;
        }
        catch (DllNotFoundException e)
        {
            string message = "Please check the Kinect SDK installation.";
            Debug.LogError(message);
            Debug.LogError(e.ToString());
            if (CalibrationText != null)
                CalibrationText.GetComponent<Text>().text = message;

            return;
        }
        catch (Exception e)
        {
            string message = e.Message + " - " + KinectWrapper.GetNuiErrorString(hr);
            Debug.LogError("Kinect not connected in usb");
            if (CalibrationText != null)
                CalibrationText.GetComponent<Text>().text = message;

            return;
        }

        if (ComputeUserMap)
        {
            // Initialize depth & label map related stuff
            usersMapSize = KinectWrapper.GetDepthWidth() * KinectWrapper.GetDepthHeight();
            usersLblTex = new Texture2D(KinectWrapper.GetDepthWidth(), KinectWrapper.GetDepthHeight());
            usersMapColors = new Color32[usersMapSize];
            usersPrevState = new ushort[usersMapSize];

            usersDepthMap = new ushort[usersMapSize];
            usersHistogramMap = new float[8192];
        }

        if (ComputeColorMap)
        {
            // Initialize color map related stuff
            usersClrTex = new Texture2D(KinectWrapper.GetColorWidth(), KinectWrapper.GetColorHeight());

            colorImage = new Color32[KinectWrapper.GetColorWidth() * KinectWrapper.GetColorHeight()];
            usersColorMap = new byte[colorImage.Length << 2];
        }

        // Try to automatically find the available avatar controllers in the scene
        if (Player1Avatars.Count == 0 && Player2Avatars.Count == 0)
        {
            AvatarController[] avatars = FindObjectsOfType(typeof(AvatarController)) as AvatarController[];

            foreach (AvatarController avatar in avatars)
            {
                Player1Avatars.Add(avatar.gameObject);
            }
        }

        // Initialize user list to contain ALL users.
        allUsers = new List<uint>();

        // Pull the AvatarController from each of the players Avatars.
        Player1Controllers = new List<AvatarController>();
        Player2Controllers = new List<AvatarController>();

        // Add each of the avatars' controllers into a list for each player.
        foreach (GameObject avatar in Player1Avatars)
        {
            if (avatar != null && avatar.activeInHierarchy)
            {
                Player1Controllers.Add(avatar.GetComponent<AvatarController>());
            }
        }

        foreach (GameObject avatar in Player2Avatars)
        {
            if (avatar != null && avatar.activeInHierarchy)
            {
                Player2Controllers.Add(avatar.GetComponent<AvatarController>());
            }
        }

        // Create the list of gesture listeners
        gestureListeners = new List<KinectGestures.GestureListenerInterface>();

        foreach (MonoBehaviour script in GestureListeners)
        {
            if (script && (script is KinectGestures.GestureListenerInterface))
            {
                KinectGestures.GestureListenerInterface listener = (KinectGestures.GestureListenerInterface)script;
                gestureListeners.Add(listener);
            }
        }

        // GUI Text.
        if (CalibrationText != null)
        {
            CalibrationText.GetComponent<Text>().text = "Vá para a frente do Kinect";
        }

        KinectInitialized = true;
    }

    void Update()
    {
        if (KinectInitialized)
        {
            // Needed by the KinectExtras' native wrapper to check for next frames
            // uncomment the line below, if you use the Extras' wrapper, but none of the Extras' managers
            // KinectWrapper.UpdateKinectSensor();

            // If the players aren't all calibrated yet, draw the user map.
            if (ComputeUserMap)
            {
                if (depthStreamHandle != IntPtr.Zero &&
                    KinectWrapper.PollDepth(depthStreamHandle, KinectWrapper.Constants.IsNearMode, ref usersDepthMap))
                {
                    UpdateUserMap();
                }
            }

            if (ComputeColorMap)
            {
                if (colorStreamHandle != IntPtr.Zero &&
                    KinectWrapper.PollColor(colorStreamHandle, ref usersColorMap, ref colorImage))
                {
                    UpdateColorMap();
                }
            }

            if (KinectWrapper.PollSkeleton(ref smoothParameters, ref skeletonFrame))
            {
                ProcessSkeleton();
            }

            // Update player 1's models if he/she is calibrated and the model is active.
            if (Player1Calibrated)
            {
                avatarController.UpdateAvatar(Player1ID);
            }
            else
            {
                //   OnGUI();
            }
        }
    }

    // Make sure to kill the Kinect on quitting.
    void OnApplicationQuit()
    {
        if (KinectInitialized)
        {
            // Shutdown OpenNI
            KinectWrapper.NuiShutdown();
            instance = null;
        }
    }


    // Update the User Map
    void UpdateUserMap()
    {
        int numOfPoints = 0;
        Array.Clear(usersHistogramMap, 0, usersHistogramMap.Length);

        // Calculate cumulative histogram for depth
        for (int i = 0; i < usersMapSize; i++)
        {
            // Only calculate for depth that contains users
            if ((usersDepthMap[i] & 7) != 0)
            {
                ushort userDepth = (ushort)(usersDepthMap[i] >> 3);
                usersHistogramMap[userDepth]++;
                numOfPoints++;
            }
        }

        if (numOfPoints > 0)
        {
            for (int i = 1; i < usersHistogramMap.Length; i++)
            {
                usersHistogramMap[i] += usersHistogramMap[i - 1];
            }

            for (int i = 0; i < usersHistogramMap.Length; i++)
            {
                usersHistogramMap[i] = 1.0f - (usersHistogramMap[i] / numOfPoints);
            }
        }

        // Dummy structure needed by the coordinate mapper
        KinectWrapper.NuiImageViewArea pcViewArea = new KinectWrapper.NuiImageViewArea
        {
            eDigitalZoom = 0,
            lCenterX = 0,
            lCenterY = 0
        };


        // Create the actual users texture based on label map and depth histogram
        Color32 clrClear = Color.clear;
        for (int i = 0; i < usersMapSize; i++)
        {
            // Flip the texture as we convert label map to color array
            int flipIndex = i; // usersMapSize - i - 1;

            ushort userMap = (ushort)(usersDepthMap[i] & 7);
            ushort userDepth = (ushort)(usersDepthMap[i] >> 3);

            ushort nowUserPixel = userMap != 0 ? (ushort)((userMap << 13) | userDepth) : userDepth;
            ushort wasUserPixel = usersPrevState[flipIndex];

            // draw only the changed pixels
            if (nowUserPixel != wasUserPixel)
            {
                usersPrevState[flipIndex] = nowUserPixel;

                if (userMap == 0)
                {
                    usersMapColors[flipIndex] = clrClear;
                }
                else
                {
                    if (colorImage != null)
                    {
                        int x = i % KinectWrapper.Constants.DepthImageWidth;
                        int y = i / KinectWrapper.Constants.DepthImageWidth;

                        int cx, cy;
                        int hr = KinectWrapper.NuiImageGetColorPixelCoordinatesFromDepthPixelAtResolution(
                            KinectWrapper.Constants.ColorImageResolution,
                            KinectWrapper.Constants.DepthImageResolution,
                            ref pcViewArea,
                            x, y, usersDepthMap[i],
                            out cx, out cy);

                        if (hr == 0)
                        {
                            int colorIndex = cx + cy * KinectWrapper.Constants.ColorImageWidth;
                            //colorIndex = usersMapSize - colorIndex - 1;
                            if (colorIndex >= 0 && colorIndex < usersMapSize)
                            {
                                Color32 colorPixel = colorImage[colorIndex];
                                usersMapColors[flipIndex] =
                                    colorPixel; // new Color(colorPixel.r / 256f, colorPixel.g / 256f, colorPixel.b / 256f, 0.9f);
                                usersMapColors[flipIndex].a = 230; // 0.9f
                            }
                        }
                    }
                    else
                    {
                        // Create a blending color based on the depth histogram
                        float histDepth = usersHistogramMap[userDepth];
                        Color c = new Color(histDepth, histDepth, histDepth, 0.9f);

                        switch (userMap % 4)
                        {
                            case 0:
                                usersMapColors[flipIndex] = Color.red * c;
                                break;
                            case 1:
                                usersMapColors[flipIndex] = Color.green * c;
                                break;
                            case 2:
                                usersMapColors[flipIndex] = Color.blue * c;
                                break;
                            case 3:
                                usersMapColors[flipIndex] = Color.magenta * c;
                                break;
                        }
                    }
                }
            }
        }

        // Draw it!
        usersLblTex.SetPixels32(usersMapColors);

        if (!DisplaySkeletonLines)
        {
            usersLblTex.Apply();
        }
    }

    // Update the Color Map
    void UpdateColorMap()
    {
        usersClrTex.SetPixels32(colorImage);
        usersClrTex.Apply();
    }

    // Assign UserId to player 1 or 2.
    void CalibrateUser(uint UserId, int UserIndex, ref KinectWrapper.NuiSkeletonData skeletonData)
    {
        // If player 1 hasn't been calibrated, assign that UserID to it.
        if (!Player1Calibrated)
        {
            // Check to make sure we don't accidentally assign player 2 to player 1.
            if (!allUsers.Contains(UserId))
            {
                if (CheckForCalibrationPose(UserId, ref Player1CalibrationPose, ref player1CalibrationData,
                        ref skeletonData))
                {
                    Player1Calibrated = true;
                    Player1ID = UserId;
                    Player1Index = UserIndex;

                    allUsers.Add(UserId);

                    foreach (AvatarController controller in Player1Controllers)
                    {
                        controller.SuccessfulCalibration(UserId);
                    }

                    // add the gestures to detect, if any
                    foreach (KinectGestures.Gestures gesture in Player1Gestures)
                    {
                        DetectGesture(UserId, gesture);
                    }

                    // notify the gesture listeners about the new user
                    foreach (KinectGestures.GestureListenerInterface listener in gestureListeners)
                    {
                        listener.UserDetected(UserId, 0);
                    }

                    // reset skeleton filters
                    ResetFilters();

                    // If we're not using 2 users, we're all calibrated.
                    //if(!TwoUsers)
                    {
                        AllPlayersCalibrated = !TwoUsers ? allUsers.Count >= 1 : allUsers.Count >= 2; // true;
                    }
                }
            }
        }
        // Otherwise, assign to player 2.
        else if (TwoUsers && !Player2Calibrated)
        {
            if (!allUsers.Contains(UserId))
            {
                if (CheckForCalibrationPose(UserId, ref Player2CalibrationPose, ref player2CalibrationData,
                        ref skeletonData))
                {
                    Player2Calibrated = true;
                    Player2ID = UserId;
                    Player2Index = UserIndex;

                    allUsers.Add(UserId);

                    foreach (AvatarController controller in Player2Controllers)
                    {
                        controller.SuccessfulCalibration(UserId);
                    }

                    // add the gestures to detect, if any
                    foreach (KinectGestures.Gestures gesture in Player2Gestures)
                    {
                        DetectGesture(UserId, gesture);
                    }

                    // notify the gesture listeners about the new user
                    foreach (KinectGestures.GestureListenerInterface listener in gestureListeners)
                    {
                        listener.UserDetected(UserId, 1);
                    }

                    // reset skeleton filters
                    ResetFilters();

                    // All users are calibrated!
                    AllPlayersCalibrated = !TwoUsers ? allUsers.Count >= 1 : allUsers.Count >= 2; // true;
                }
            }
        }

        // If all users are calibrated, stop trying to find them.
        if (AllPlayersCalibrated)
        {
            if (CalibrationText != null)
            {
                OnRecordingBegin.Invoke();
            }
        }
    }

    // Remove a lost UserId
    void RemoveUser(uint UserId)
    {
        // If we lose player 1...
        if (UserId == Player1ID)
        {
            // Null out the ID and reset all the models associated with that ID.
            Player1ID = 0;
            Player1Index = 0;
            Player1Calibrated = false;

            foreach (AvatarController controller in Player1Controllers)
            {
                controller.ResetToInitialPosition();
            }

            foreach (KinectGestures.GestureListenerInterface listener in gestureListeners)
            {
                listener.UserLost(UserId, 0);
            }

            player1CalibrationData.userId = 0;
        }

        // If we lose player 2...
        if (UserId == Player2ID)
        {
            // Null out the ID and reset all the models associated with that ID.
            Player2ID = 0;
            Player2Index = 0;
            Player2Calibrated = false;

            foreach (AvatarController controller in Player2Controllers)
            {
                controller.ResetToInitialPosition();
            }

            foreach (KinectGestures.GestureListenerInterface listener in gestureListeners)
            {
                listener.UserLost(UserId, 1);
            }

            player2CalibrationData.userId = 0;
        }

        // Clear gestures list for this user
        ClearGestures(UserId);

        // Remove from global users list
        allUsers.Remove(UserId);
        AllPlayersCalibrated = !TwoUsers ? allUsers.Count >= 1 : allUsers.Count >= 2; // false;

        if (CalibrationText != null)
        {
            CalibrationText.text = "Vá para a frente do Kinect";
            OnRecordingFinish.Invoke();
        }
    }

    // Some internal constants
    private const int stateTracked = (int)KinectWrapper.NuiSkeletonPositionTrackingState.Tracked;
    private const int stateNotTracked = (int)KinectWrapper.NuiSkeletonPositionTrackingState.NotTracked;

    private int[] mustBeTrackedJoints =
    {
        (int)KinectWrapper.NuiSkeletonPositionIndex.AnkleLeft,
        (int)KinectWrapper.NuiSkeletonPositionIndex.FootLeft,
        (int)KinectWrapper.NuiSkeletonPositionIndex.AnkleRight,
        (int)KinectWrapper.NuiSkeletonPositionIndex.FootRight,
    };

    // Process the skeleton data
    void ProcessSkeleton()
    {
        List<uint> lostUsers = new List<uint>();
        lostUsers.AddRange(allUsers);

        // Calculate the time since last update
        float currentNuiTime = Time.realtimeSinceStartup;
        float deltaNuiTime = currentNuiTime - lastNuiTime;

        for (int i = 0; i < KinectWrapper.Constants.NuiSkeletonCount; i++)
        {
            KinectWrapper.NuiSkeletonData skeletonData = skeletonFrame.SkeletonData[i];
            uint userId = skeletonData.dwTrackingID;

            if (skeletonData.eTrackingState == KinectWrapper.NuiSkeletonTrackingState.SkeletonTracked)
            {
                // get the skeleton position
                Vector3 skeletonPos = kinectToWorld.MultiplyPoint3x4(skeletonData.Position);

                if (!AllPlayersCalibrated)
                {
                    // check if this is the closest user
                    bool bClosestUser = true;

                    if (DetectClosestUser)
                    {
                        for (int j = 0; j < KinectWrapper.Constants.NuiSkeletonCount; j++)
                        {
                            if (j != i)
                            {
                                KinectWrapper.NuiSkeletonData skeletonDataOther = skeletonFrame.SkeletonData[j];

                                if ((skeletonDataOther.eTrackingState ==
                                     KinectWrapper.NuiSkeletonTrackingState.SkeletonTracked) &&
                                    (Mathf.Abs(kinectToWorld.MultiplyPoint3x4(skeletonDataOther.Position).z) <
                                     Mathf.Abs(skeletonPos.z)))
                                {
                                    bClosestUser = false;
                                    break;
                                }
                            }
                        }
                    }

                    if (bClosestUser)
                    {
                        Debug.Log("Wave to kinect to start capturing");
                        CalibrateUser(userId, i + 1, ref skeletonData);
                    }
                }

                if (userId == Player1ID && Mathf.Abs(skeletonPos.z) >= MinUserDistance &&
                    (MaxUserDistance <= 0f || Mathf.Abs(skeletonPos.z) <= MaxUserDistance))
                {
                    player1Index = i;

                    // get player position
                    player1Pos = skeletonPos;

                    // apply tracking state filter first
                    trackingStateFilter[0].UpdateFilter(ref skeletonData);

                    // fixup skeleton to improve avatar appearance.
                    if (UseClippedLegsFilter && clippedLegsFilter[0] != null)
                    {
                        clippedLegsFilter[0].FilterSkeleton(ref skeletonData, deltaNuiTime);
                    }

                    if (UseSelfIntersectionConstraint && selfIntersectionConstraint != null)
                    {
                        selfIntersectionConstraint.Constrain(ref skeletonData);
                    }

                    // get joints' position and rotation
                    for (int j = 0; j < (int)KinectWrapper.NuiSkeletonPositionIndex.Count; j++)
                    {
                        bool playerTracked = IgnoreInferredJoints
                            ? (int)skeletonData.eSkeletonPositionTrackingState[j] == stateTracked
                            : (Array.BinarySearch(mustBeTrackedJoints, j) >= 0
                                ? (int)skeletonData.eSkeletonPositionTrackingState[j] == stateTracked
                                : (int)skeletonData.eSkeletonPositionTrackingState[j] != stateNotTracked);
                        player1JointsTracked[j] = player1PrevTracked[j] && playerTracked;
                        player1PrevTracked[j] = playerTracked;

                        if (player1JointsTracked[j])
                        {
                            player1JointsPos[j] = kinectToWorld.MultiplyPoint3x4(skeletonData.SkeletonPositions[j]);
                            //player1JointsOri[j] = jointOrients[j].absoluteRotation.rotationMatrix * flipMatrix;
                        }
                    }

                    // draw the skeleton on top of texture
                    if (DisplaySkeletonLines && ComputeUserMap)
                    {
                        DrawSkeleton(usersLblTex, ref skeletonData, ref player1JointsTracked);
                        usersLblTex.Apply();
                    }

                    // calculate joint orientations
                    KinectWrapper.GetSkeletonJointOrientation(ref player1JointsPos, ref player1JointsTracked,
                        ref player1JointsOri);

                    // filter orientation constraints
                    if (UseBoneOrientationsConstraint && boneConstraintsFilter != null)
                    {
                        boneConstraintsFilter.Constrain(ref player1JointsOri, ref player1JointsTracked);
                    }

                    // filter joint orientations.
                    // it should be performed after all joint position modifications.
                    if (UseBoneOrientationsFilter && boneOrientationFilter[0] != null)
                    {
                        boneOrientationFilter[0].UpdateFilter(ref skeletonData, ref player1JointsOri);
                    }

                    // get player rotation
                    player1Ori = player1JointsOri[(int)KinectWrapper.NuiSkeletonPositionIndex.HipCenter];

                    // check for gestures
                    if (Time.realtimeSinceStartup >= gestureTrackingAtTime[0])
                    {
                        int listGestureSize = player1Gestures.Count;
                        float timestampNow = Time.realtimeSinceStartup;
                        string sDebugGestures = string.Empty; // "Tracked Gestures:\n";

                        for (int g = 0; g < listGestureSize; g++)
                        {
                            KinectGestures.GestureData gestureData = player1Gestures[g];

                            if ((timestampNow >= gestureData.startTrackingAtTime) &&
                                !IsConflictingGestureInProgress(gestureData))
                            {
                                KinectGestures.CheckForGesture(userId, ref gestureData, Time.realtimeSinceStartup,
                                    ref player1JointsPos, ref player1JointsTracked);
                                player1Gestures[g] = gestureData;

                                if (gestureData.complete)
                                {
                                    gestureTrackingAtTime[0] = timestampNow + MinTimeBetweenGestures;
                                }

                                //if(gestureData.state > 0)
                                {
                                    sDebugGestures += string.Format("{0} - state: {1}, time: {2:F1}, progress: {3}%\n",
                                        gestureData.gesture, gestureData.state,
                                        gestureData.timestamp,
                                        (int)(gestureData.progress * 100 + 0.5f));
                                }
                            }
                        }

                        if (GesturesDebugText)
                        {
                            sDebugGestures += string.Format("\n HandLeft: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.HandLeft]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.HandLeft].ToString()
                                    : "");
                            sDebugGestures += string.Format("\n HandRight: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.HandRight]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.HandRight].ToString()
                                    : "");
                            sDebugGestures += string.Format("\n ElbowLeft: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.ElbowLeft]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.ElbowLeft].ToString()
                                    : "");
                            sDebugGestures += string.Format("\n ElbowRight: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.ElbowRight]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.ElbowRight]
                                        .ToString()
                                    : "");

                            sDebugGestures += string.Format("\n ShoulderLeft: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.ShoulderLeft]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.ShoulderLeft]
                                        .ToString()
                                    : "");
                            sDebugGestures += string.Format("\n ShoulderRight: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.ShoulderRight]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.ShoulderRight]
                                        .ToString()
                                    : "");

                            sDebugGestures += string.Format("\n Neck: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.ShoulderCenter]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.ShoulderCenter]
                                        .ToString()
                                    : "");
                            sDebugGestures += string.Format("\n Hips: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.HipCenter]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.HipCenter].ToString()
                                    : "");
                            sDebugGestures += string.Format("\n HipLeft: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.HipLeft]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.HipLeft].ToString()
                                    : "");
                            sDebugGestures += string.Format("\n HipRight: {0}",
                                player1JointsTracked[(int)KinectWrapper.NuiSkeletonPositionIndex.HipRight]
                                    ? player1JointsPos[(int)KinectWrapper.NuiSkeletonPositionIndex.HipRight].ToString()
                                    : "");

                            GesturesDebugText.text = sDebugGestures;
                        }
                    }
                }
                else if (userId == Player2ID && Mathf.Abs(skeletonPos.z) >= MinUserDistance &&
                         (MaxUserDistance <= 0f || Mathf.Abs(skeletonPos.z) <= MaxUserDistance))
                {
                    player2Index = i;

                    // get player position
                    player2Pos = skeletonPos;

                    // apply tracking state filter first
                    trackingStateFilter[1].UpdateFilter(ref skeletonData);

                    // fixup skeleton to improve avatar appearance.
                    if (UseClippedLegsFilter && clippedLegsFilter[1] != null)
                    {
                        clippedLegsFilter[1].FilterSkeleton(ref skeletonData, deltaNuiTime);
                    }

                    if (UseSelfIntersectionConstraint && selfIntersectionConstraint != null)
                    {
                        selfIntersectionConstraint.Constrain(ref skeletonData);
                    }

                    // get joints' position and rotation
                    for (int j = 0; j < (int)KinectWrapper.NuiSkeletonPositionIndex.Count; j++)
                    {
                        bool playerTracked = IgnoreInferredJoints
                            ? (int)skeletonData.eSkeletonPositionTrackingState[j] == stateTracked
                            : (Array.BinarySearch(mustBeTrackedJoints, j) >= 0
                                ? (int)skeletonData.eSkeletonPositionTrackingState[j] == stateTracked
                                : (int)skeletonData.eSkeletonPositionTrackingState[j] != stateNotTracked);
                        player2JointsTracked[j] = player2PrevTracked[j] && playerTracked;
                        player2PrevTracked[j] = playerTracked;

                        if (player2JointsTracked[j])
                        {
                            player2JointsPos[j] = kinectToWorld.MultiplyPoint3x4(skeletonData.SkeletonPositions[j]);
                        }
                    }

                    // draw the skeleton on top of texture
                    if (DisplaySkeletonLines && ComputeUserMap)
                    {
                        DrawSkeleton(usersLblTex, ref skeletonData, ref player2JointsTracked);
                        usersLblTex.Apply();
                    }

                    // calculate joint orientations
                    KinectWrapper.GetSkeletonJointOrientation(ref player2JointsPos, ref player2JointsTracked,
                        ref player2JointsOri);

                    // filter orientation constraints
                    if (UseBoneOrientationsConstraint && boneConstraintsFilter != null)
                    {
                        boneConstraintsFilter.Constrain(ref player2JointsOri, ref player2JointsTracked);
                    }

                    // filter joint orientations.
                    // it should be performed after all joint position modifications.
                    if (UseBoneOrientationsFilter && boneOrientationFilter[1] != null)
                    {
                        boneOrientationFilter[1].UpdateFilter(ref skeletonData, ref player2JointsOri);
                    }

                    // get player rotation
                    player2Ori = player2JointsOri[(int)KinectWrapper.NuiSkeletonPositionIndex.HipCenter];

                    // check for gestures
                    if (Time.realtimeSinceStartup >= gestureTrackingAtTime[1])
                    {
                        int listGestureSize = player2Gestures.Count;
                        float timestampNow = Time.realtimeSinceStartup;

                        for (int g = 0; g < listGestureSize; g++)
                        {
                            KinectGestures.GestureData gestureData = player2Gestures[g];

                            if ((timestampNow >= gestureData.startTrackingAtTime) &&
                                !IsConflictingGestureInProgress(gestureData))
                            {
                                KinectGestures.CheckForGesture(userId, ref gestureData, Time.realtimeSinceStartup,
                                    ref player2JointsPos, ref player2JointsTracked);
                                player2Gestures[g] = gestureData;

                                if (gestureData.complete)
                                {
                                    gestureTrackingAtTime[1] = timestampNow + MinTimeBetweenGestures;
                                }
                            }
                        }
                    }
                }

                lostUsers.Remove(userId);
            }
        }

        // update the nui-timer
        lastNuiTime = currentNuiTime;

        // remove the lost users if any
        if (lostUsers.Count > 0)
        {
            foreach (uint userId in lostUsers)
            {
                RemoveUser(userId);
                // Encerrar captura
            }

            lostUsers.Clear();
        }
    }

    // Draws the skeleton in the given texture
    private void DrawSkeleton(Texture2D aTexture, ref KinectWrapper.NuiSkeletonData skeletonData,
        ref bool[] playerJointsTracked)
    {
        int jointsCount = (int)KinectWrapper.NuiSkeletonPositionIndex.Count;

        for (int i = 0; i < jointsCount; i++)
        {
            int parent = KinectWrapper.GetSkeletonJointParent(i);

            if (playerJointsTracked[i] && playerJointsTracked[parent])
            {
                Vector3 posParent = KinectWrapper.MapSkeletonPointToDepthPoint(skeletonData.SkeletonPositions[parent]);
                Vector3 posJoint = KinectWrapper.MapSkeletonPointToDepthPoint(skeletonData.SkeletonPositions[i]);
                DrawLine(aTexture, (int)posParent.x, (int)posParent.y, (int)posJoint.x, (int)posJoint.y, Color.yellow);
            }
        }
    }

    // Draws a line in a texture
    private void DrawLine(Texture2D a_Texture, int x1, int y1, int x2, int y2, Color a_Color)
    {
        int width = a_Texture.width; // KinectWrapper.Constants.DepthImageWidth;
        int height = a_Texture.height; // KinectWrapper.Constants.DepthImageHeight;

        int dy = y2 - y1;
        int dx = x2 - x1;

        int stepy = 1;
        if (dy < 0)
        {
            dy = -dy;
            stepy = -1;
        }

        int stepx = 1;
        if (dx < 0)
        {
            dx = -dx;
            stepx = -1;
        }

        dy <<= 1;
        dx <<= 1;

        if (x1 >= 0 && x1 < width && y1 >= 0 && y1 < height)
            for (int x = -1; x <= 1; x++)
            for (int y = -1; y <= 1; y++)
                a_Texture.SetPixel(x1 + x, y1 + y, a_Color);

        if (dx > dy)
        {
            int fraction = dy - (dx >> 1);

            while (x1 != x2)
            {
                if (fraction >= 0)
                {
                    y1 += stepy;
                    fraction -= dx;
                }

                x1 += stepx;
                fraction += dy;

                if (x1 >= 0 && x1 < width && y1 >= 0 && y1 < height)
                    for (int x = -1; x <= 1; x++)
                    for (int y = -1; y <= 1; y++)
                        a_Texture.SetPixel(x1 + x, y1 + y, a_Color);
            }
        }
        else
        {
            int fraction = dx - (dy >> 1);

            while (y1 != y2)
            {
                if (fraction >= 0)
                {
                    x1 += stepx;
                    fraction -= dy;
                }

                y1 += stepy;
                fraction += dx;

                if (x1 >= 0 && x1 < width && y1 >= 0 && y1 < height)
                    for (int x = -1; x <= 1; x++)
                    for (int y = -1; y <= 1; y++)
                        a_Texture.SetPixel(x1 + x, y1 + y, a_Color);
            }
        }
    }

    // Convert the matrix to quaternion, taking care of the mirroring
    private Quaternion ConvertMatrixToQuat(Matrix4x4 mOrient, int joint, bool flip)
    {
        Vector4 vZ = mOrient.GetColumn(2);
        Vector4 vY = mOrient.GetColumn(1);

        if (!flip)
        {
            vZ.y = -vZ.y;
            vY.x = -vY.x;
            vY.z = -vY.z;
        }
        else
        {
            vZ.x = -vZ.x;
            vZ.y = -vZ.y;
            vY.z = -vY.z;
        }

        if (vZ.x != 0.0f || vZ.y != 0.0f || vZ.z != 0.0f)
            return Quaternion.LookRotation(vZ, vY);
        else
            return Quaternion.identity;
    }

    // Return the index of gesture in the list, or -1 if not found
    private int GetGestureIndex(uint UserId, KinectGestures.Gestures gesture)
    {
        if (UserId == Player1ID)
        {
            int listSize = player1Gestures.Count;
            for (int i = 0; i < listSize; i++)
            {
                if (player1Gestures[i].gesture == gesture)
                    return i;
            }
        }
        else if (UserId == Player2ID)
        {
            int listSize = player2Gestures.Count;
            for (int i = 0; i < listSize; i++)
            {
                if (player2Gestures[i].gesture == gesture)
                    return i;
            }
        }

        return -1;
    }

    private bool IsConflictingGestureInProgress(KinectGestures.GestureData gestureData)
    {
        foreach (KinectGestures.Gestures gesture in gestureData.checkForGestures)
        {
            int index = GetGestureIndex(gestureData.userId, gesture);

            if (index >= 0)
            {
                if (gestureData.userId == Player1ID)
                {
                    if (player1Gestures[index].progress > 0f)
                        return true;
                }
                else if (gestureData.userId == Player2ID)
                {
                    if (player2Gestures[index].progress > 0f)
                        return true;
                }
            }
        }

        return false;
    }

    // Check if the calibration pose is complete for given user
    private bool CheckForCalibrationPose(uint userId, ref KinectGestures.Gestures calibrationGesture,
        ref KinectGestures.GestureData gestureData, ref KinectWrapper.NuiSkeletonData skeletonData)
    {
        if (calibrationGesture == KinectGestures.Gestures.None)
            return true;

        // init gesture data if needed
        if (gestureData.userId != userId)
        {
            gestureData.userId = userId;
            gestureData.gesture = calibrationGesture;
            gestureData.state = 0;
            gestureData.joint = 0;
            gestureData.progress = 0f;
            gestureData.complete = false;
            gestureData.cancelled = false;
        }

        // Get temporary joints' position
        int skeletonJointsCount = (int)KinectWrapper.NuiSkeletonPositionIndex.Count;
        bool[] jointsTracked = new bool[skeletonJointsCount];
        Vector3[] jointsPos = new Vector3[skeletonJointsCount];

        int stateTracked = (int)KinectWrapper.NuiSkeletonPositionTrackingState.Tracked;
        int stateNotTracked = (int)KinectWrapper.NuiSkeletonPositionTrackingState.NotTracked;

        int[] mustBeTrackedJoints =
        {
            (int)KinectWrapper.NuiSkeletonPositionIndex.AnkleLeft,
            (int)KinectWrapper.NuiSkeletonPositionIndex.FootLeft,
            (int)KinectWrapper.NuiSkeletonPositionIndex.AnkleRight,
            (int)KinectWrapper.NuiSkeletonPositionIndex.FootRight,
        };

        for (int j = 0; j < skeletonJointsCount; j++)
        {
            jointsTracked[j] = Array.BinarySearch(mustBeTrackedJoints, j) >= 0
                ? (int)skeletonData.eSkeletonPositionTrackingState[j] == stateTracked
                : (int)skeletonData.eSkeletonPositionTrackingState[j] != stateNotTracked;

            if (jointsTracked[j])
            {
                jointsPos[j] = kinectToWorld.MultiplyPoint3x4(skeletonData.SkeletonPositions[j]);
            }
        }

        // Estimate the gesture progess
        KinectGestures.CheckForGesture(userId, ref gestureData, Time.realtimeSinceStartup,
            ref jointsPos, ref jointsTracked);

        // check if gesture is complete
        if (gestureData.complete)
        {
            gestureData.userId = 0;
            return true;
        }

        return false;
    }
}				
			
Nesta página