Kinnect中AvatarController腳本翻譯

AvatarController腳本翻譯

using UnityEngine;
//using Windows.Kinect;

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using System.Text; 


/// <summary>
/// Avatar controller is the component that transfers the captured user motion to a humanoid model (avatar).
/// </summary>
[RequireComponent(typeof(Animator))]
public class AvatarController : MonoBehaviour
{   
    [Tooltip("Index of the player, tracked by this component. 0 means the 1st player, 1 - the 2nd one, 2 - the 3rd one, etc.")]
    //索引
    public int playerIndex = 0;

    [Tooltip("Whether the avatar is facing the player or not.")]
    //人物是否面對玩家
    public bool mirroredMovement = false;

    [Tooltip("Whether the avatar is allowed to move vertically or not.")]
    //人物是否允許唄垂直移動
    public bool verticalMovement = false;

    [Tooltip("Whether the avatar's root motion is applied by other component or script.")]
    //人物的根動作是否適用於其他組件或腳本。
    public bool externalRootMotion = false;

    [Tooltip("Whether the head rotation is controlled externally (e.g. by VR-headset)" )]
    //頭部旋轉是否由外部控制(例如,由vr-耳機)
    public bool externalHeadRotation = false;

    [Tooltip("Whether the finger orientations are allowed or not.")]
    //手指朝向是否允許。
    public bool fingerOrientations = false;

    [Tooltip("Rate at which the avatar will move through the scene.")]
    //人物在鏡頭中的移動速度
    public float moveRate = 1f;

    [Tooltip("Smooth factor used for avatar movements and joint rotations.")]
    //用於人物運動和關節旋轉的平滑因子
    public float smoothFactor = 10f;

    [Tooltip("Game object this transform is relative to (optional).")]
    //這個轉換是相對於(可選的)。隨人物的變換而變換
    public GameObject offsetNode;

    [Tooltip("If enabled, makes the avatar position relative to this camera to be the same as the player's position to the sensor.")]
    //如果啓用,則使化身相對於該攝像機的位置與玩家對傳感器的位置相同。
    public Camera posRelativeToCamera;

    [Tooltip("Whether the avatar's position should match the color image (in Pos-rel-to-camera mode only).")]
    //人物的位置是否應該與彩色圖像相匹配(僅在相機-鏡頭模式下)。
    public bool posRelOverlayColor = false;

    [Tooltip("Whether z-axis movement needs to be inverted (Pos-Relative mode only).")]
    //z軸運動是否需要反轉(僅是相對模式)
    public bool posRelInvertedZ = false;

    [Tooltip("Whether the avatar's feet must stick to the ground.")]
    //人物的腳是否必須貼在地面上。
    public bool groundedFeet = false;

    [Tooltip("Whether to apply the humanoid muscle limits or not.")]
    //是否適用於人類的肌肉限制。
    public bool applyMuscleLimits = false;

    [Tooltip("Whether to flip left and right, relative to the sensor.")]
    //相對於傳感器,是否要翻轉左和右。
    public bool flipLeftRight = false;


    [Tooltip("Vertical offset of the avatar with respect to the position of user's spine-base.")]
    //在用戶的脊柱基礎上,對化身的垂直偏移量。
    [Range(-0.5f, 0.5f)]
    public float verticalOffset = 0f;

    [Tooltip("Forward (Z) offset of the avatar with respect to the position of user's spine-base.")]
    //向前(Z)在用戶的脊柱基礎上的位置偏移。
    [Range(-0.5f, 0.5f)]
    public float forwardOffset = 0f;

    // userId of the player
    [NonSerialized]
    //人物Id
    public Int64 playerId = 0;


    // The body root node
    //人物根節點
    protected Transform bodyRoot;

    // Variable to hold all them bones. It will initialize the same size as initialRotations.
    //把所有的骨頭都固定住,將初始化與初始旋轉相同的大小。
    protected Transform[] bones;

    // Rotations of the bones when the Kinect tracking starts.
    //當Kinect追蹤開始時,骨頭的旋轉。
    protected Quaternion[] initialRotations;
    protected Quaternion[] localRotations;
    protected bool[] isBoneDisabled;

    // Local rotations of finger bones
    //手指骨局部旋轉
    protected Dictionary<HumanBodyBones, Quaternion> fingerBoneLocalRotations = new Dictionary<HumanBodyBones, Quaternion>();
    protected Dictionary<HumanBodyBones, Vector3> fingerBoneLocalAxes = new Dictionary<HumanBodyBones, Vector3>();

    // Initial position and rotation of the transform
    //轉換的初始位置和旋轉
    protected Vector3 initialPosition;
    protected Quaternion initialRotation;
    protected Vector3 initialHipsPosition;//初始化臀部位置
    protected Quaternion initialHipsRotation;//初始化臀部旋轉角度

    protected Vector3 offsetNodePos;
    protected Quaternion offsetNodeRot;
    protected Vector3 bodyRootPosition;

    // Calibration Offset Variables for Character Position.
    //對字符位置的校正偏置變量。
    [NonSerialized]
    public bool offsetCalibrated = false;
    protected Vector3 offsetPos = Vector3.zero;
    //protected float xOffset, yOffset, zOffset;
    //private Quaternion originalRotation;

    private Animator animatorComponent = null;
    private HumanPoseHandler humanPoseHandler = null;
    private HumanPose humanPose = new HumanPose();

    // whether the parent transform obeys physics
    //父變換是否遵循物理
    protected bool isRigidBody = false;

    // private instance of the KinectManager
    //KinectManager的私有實例
    protected KinectManager kinectManager;

    // last hand events
    //最後手事件
    private InteractionManager.HandEventType lastLeftHandEvent = InteractionManager.HandEventType.Release;
    private InteractionManager.HandEventType lastRightHandEvent = InteractionManager.HandEventType.Release;

    // fist states
    private bool bLeftFistDone = false;
    private bool bRightFistDone = false;

    // grounder constants and variables
    //滾地球常量和變量
    private const int raycastLayers = ~2;  // Ignore Raycast//忽略Raycast
    private const float maxFootDistanceGround = 0.02f;  // maximum distance from lower foot to the ground//從下腳到地面的最大距離
    private const float maxFootDistanceTime = 0.2f; // 1.0f;  // maximum allowed time, the lower foot to be distant from the ground//最大允許時間,下腳距離地面較遠
    private Transform leftFoot, rightFoot;

    private float fFootDistanceInitial = 0f;
    private float fFootDistance = 0f;
    private float fFootDistanceTime = 0f;


    /// <summary>
    /// Gets the number of bone transforms (array length).
    /// 得到骨轉換的數量(數組長度)。
    /// </summary>
    /// <returns>The number of bone transforms.</returns>
    public int GetBoneTransformCount()
    {
        return bones != null ? bones.Length : 0;
    }

    /// <summary>
    /// Gets the bone transform by index.
    /// 通過索引來得到骨頭的變化。
    /// </summary>
    /// <returns>The bone transform.</returns>
    /// <param name="index">Index</param>
    public Transform GetBoneTransform(int index)
    {
        if(index >= 0 && index < bones.Length)
        {
            return bones[index];
        }

        return null;
    }

    /// <summary>
    /// Get joint position with respect of player world and kinect offsets   ( //!!still some problems with accurate Y pos, probably connected with kinect sensor height estimation ) 
    /// 得到在世界座標上準確的關節位置和kinect偏移量(//!!!還有一些問題是精確的Y pos,可能與kinect傳感器高度評估有關)
    /// </summary>
    /// <param name="jointType"></param>
    /// <returns></returns>
    public Vector3 GetJointWorldPos( KinectInterop.JointType jointType )
    {
        if( !kinectManager )
        {
            return Vector3.zero;
        }

        Vector3 jointPosition = kinectManager.GetJointPosition( playerId, (int)jointType );
        Vector3 worldPosition = new Vector3(
            jointPosition.x - offsetPos.x, 
//            jointPosition.y - offsetPos.y + kinectManager.sensorHeight,  //!! this should be better investigated .. 
            jointPosition.y + offsetPos.y - kinectManager.sensorHeight,  //!! this workds better on my example 
            !mirroredMovement && !posRelativeToCamera ? (-jointPosition.z - offsetPos.z) : (jointPosition.z - offsetPos.z));

        Quaternion posRotation = mirroredMovement ? Quaternion.Euler (0f, 180f, 0f) * initialRotation : initialRotation;
        worldPosition = posRotation * worldPosition;

        return bodyRootPosition + worldPosition;
    }

    /// <summary>
    /// Disables the bone and optionally resets its orientation.
    /// 禁用骨頭,並可選擇重新設置其方向。
    /// </summary>
    /// <param name="index">Bone index.</param>
    /// <param name="resetBone">If set to <c>true</c> resets bone orientation.</param>
    public void DisableBone(int index, bool resetBone)
    {
        if(index >= 0 && index < bones.Length)
        {
            isBoneDisabled[index] = true;

            if (resetBone && bones[index] != null) 
            {
                bones[index].rotation = localRotations[index];
            }
        }
    }

    /// <summary>
    /// Enables the bone, so AvatarController could update its orientation.
    /// 骨骼是否激活,因此,它可以更新它的方向。
    /// </summary>
    /// <param name="index">Bone index.</param>
    public void EnableBone(int index)
    {
        if(index >= 0 && index < bones.Length)
        {
            isBoneDisabled[index] = false;
        }
    }

    /// <summary>
    /// Determines whether the bone orientation update is enabled or not.
    /// 確定是否啓用了骨定位更新。
    /// </summary>
    /// <returns><c>true</c> if the bone update is enabled; otherwise, <c>false</c>.</returns>
    /// <param name="index">Bone index.</param>
    public bool IsBoneEnabled(int index)
    {
        if(index >= 0 && index < bones.Length)
        {
            return !isBoneDisabled[index];
        }

        return false;
    }

    /// <summary>
    /// Gets the bone index by joint type.
    /// 通過關節類型得到骨骼索引。
    /// </summary>
    /// <returns>The bone index.</returns>
    /// <param name="joint">Joint type</param>
    /// <param name="bMirrored">If set to <c>true</c> gets the mirrored joint index.</param>
    public int GetBoneIndexByJoint(KinectInterop.JointType joint, bool bMirrored)
    {
        int boneIndex = -1;

        if(jointMap2boneIndex.ContainsKey(joint))
        {
            boneIndex = !bMirrored ? jointMap2boneIndex[joint] : mirrorJointMap2boneIndex[joint];
        }

        return boneIndex;
    }

    /// <summary>
    /// Gets the special index by two joint types.
    /// 通過兩種關節類型得到特殊的索引。
    /// </summary>
    /// <returns>The spec index by joint.</returns>
    /// <param name="joint1">Joint 1 type.</param>
    /// <param name="joint2">Joint 2 type.</param>
    /// <param name="bMirrored">If set to <c>true</c> gets the mirrored joint index.</param>
    public int GetSpecIndexByJoint(KinectInterop.JointType joint1, KinectInterop.JointType joint2, bool bMirrored)
    {
        int boneIndex = -1;

        if((joint1 == KinectInterop.JointType.ShoulderLeft && joint2 == KinectInterop.JointType.SpineShoulder) ||
           (joint2 == KinectInterop.JointType.ShoulderLeft && joint1 == KinectInterop.JointType.SpineShoulder))
        {
            return (!bMirrored ? 25 : 26);
        }
        else if((joint1 == KinectInterop.JointType.ShoulderRight && joint2 == KinectInterop.JointType.SpineShoulder) ||
                (joint2 == KinectInterop.JointType.ShoulderRight && joint1 == KinectInterop.JointType.SpineShoulder))
        {
            return (!bMirrored ? 26 : 25);
        }
        else if((joint1 == KinectInterop.JointType.HandTipLeft && joint2 == KinectInterop.JointType.HandLeft) ||
                (joint2 == KinectInterop.JointType.HandTipLeft && joint1 == KinectInterop.JointType.HandLeft))
        {
            return (!bMirrored ? 27 : 28);
        }
        else if((joint1 == KinectInterop.JointType.HandTipRight && joint2 == KinectInterop.JointType.HandRight) ||
                (joint2 == KinectInterop.JointType.HandTipRight && joint1 == KinectInterop.JointType.HandRight))
        {
            return (!bMirrored ? 28 : 27);
        }
        else if((joint1 == KinectInterop.JointType.ThumbLeft && joint2 == KinectInterop.JointType.HandLeft) ||
                (joint2 == KinectInterop.JointType.ThumbLeft && joint1 == KinectInterop.JointType.HandLeft))
        {
            return (!bMirrored ? 29 : 30);
        }
        else if((joint1 == KinectInterop.JointType.ThumbRight && joint2 == KinectInterop.JointType.HandRight) ||
                (joint2 == KinectInterop.JointType.ThumbRight && joint1 == KinectInterop.JointType.HandRight))
        {
            return (!bMirrored ? 30 : 29);
        }

        return boneIndex;
    }


    // transform caching gives performance boost since Unity calls GetComponent<Transform>() each time you call transform 
    //轉換緩存提供了性能提升,因爲每次調用轉換時都調用GetComponent的GetComponent()
    private Transform _transformCache;
    public new Transform transform
    {
        get
        {
            if (!_transformCache) 
            {
                _transformCache = base.transform;
            }

            return _transformCache;
        }
    }


    public void Awake()
    {   
        // check for double start
        if(bones != null)
            return;
        if(!gameObject.activeInHierarchy) 
            return;

        // inits the bones array
        //初始化骨頭數組
        bones = new Transform[31];

        // get the animator reference
        //得到動畫組件
        animatorComponent = GetComponent<Animator>();

        // Map bones to the points the Kinect tracks
        //將骨頭映射到Kinect追蹤的點
        MapBones();

        // Set model's arms to be in T-pose, if needed
        //如果需要,將模型的手臂設置爲t型
        SetModelArmsInTpose();

        // Initial rotations and directions of the bones.
        //最初的旋轉和骨骼的方向。
        initialRotations = new Quaternion[bones.Length];
        localRotations = new Quaternion[bones.Length];
        isBoneDisabled = new bool[bones.Length];

        // Get initial bone rotations
        //得到初始骨旋轉
        GetInitialRotations();

        // enable all bones
        //不激活所有的骨骼
        for(int i = 0; i < bones.Length; i++)
        {
            isBoneDisabled[i] = false;
        }

        // get initial distance to ground
        //到達地面的初始距離
        fFootDistanceInitial = GetDistanceToGround();
        fFootDistance = 0f;
        fFootDistanceTime = 0f;

        // if parent transform uses physics
        //如果父變換使用物理
        isRigidBody = (gameObject.GetComponent<Rigidbody>() != null);

        // get the pose handler reference
        //獲取姿勢處理程序引用
        if (animatorComponent && animatorComponent.avatar && animatorComponent.avatar.isHuman) 
        {
            //Transform hipsTransform = animator.GetBoneTransform(HumanBodyBones.Hips);
            //Transform rootTransform = hipsTransform.parent;
            Transform rootTransform = transform;

            humanPoseHandler = new HumanPoseHandler(animatorComponent.avatar, rootTransform);
            humanPoseHandler.GetHumanPose(ref humanPose);
        }
    }


    // applies the muscle limits for humanoid avatar
    //適用於類人的肌力限制
    private void CheckMuscleLimits()
    {
        if (humanPoseHandler == null)
            return;

        humanPoseHandler.GetHumanPose(ref humanPose);

        //Debug.Log(playerId + " - Trans: " + transform.position + ", body: " + humanPose.bodyPosition);

        bool isPoseChanged = false;

        float muscleMin = -1f;
        float muscleMax = 1f;

        for (int i = 0; i < humanPose.muscles.Length; i++) 
        {
            if (float.IsNaN(humanPose.muscles[i])) 
            {
                //humanPose.muscles[i] = 0f;
                continue;
            }

            if (humanPose.muscles[i] < muscleMin) 
            {
                humanPose.muscles[i] = muscleMin;
                isPoseChanged = true;
            }
            else if (humanPose.muscles[i] > muscleMax) 
            {
                humanPose.muscles[i] = muscleMax;
                isPoseChanged = true;
            }
        }

        if (isPoseChanged) 
        {
            Quaternion localBodyRot = Quaternion.Inverse(transform.rotation) * humanPose.bodyRotation;

            // recover the body position & orientation
            //humanPose.bodyPosition = Vector3.zero;
            //humanPose.bodyPosition.y = initialHipsPosition.y;
            humanPose.bodyPosition = initialHipsPosition;
            humanPose.bodyRotation = localBodyRot; // Quaternion.identity;

            humanPoseHandler.SetHumanPose(ref humanPose);
            //Debug.Log("  Human pose updated.");
        }

    }


    /// <summary>
    /// Updates the avatar each frame.
    /// 更新化身每一幀。
    /// </summary>
    /// <param name="UserID">User ID</param>
    public void UpdateAvatar(Int64 UserID)
    {   
        if(!gameObject.activeInHierarchy) 
            return;

        // Get the KinectManager instance
        if(kinectManager == null)
        {
            kinectManager = KinectManager.Instance;
        }

        // move the avatar to its Kinect position
        //將化身移動到它的Kinect位置
        if (!externalRootMotion)
        {
            MoveAvatar(UserID);
        }

        // get the left hand state and event
        //得到左邊的狀態和事件
        if (kinectManager && kinectManager.GetJointTrackingState(UserID, (int)KinectInterop.JointType.HandLeft) != KinectInterop.TrackingState.NotTracked)
        {
            KinectInterop.HandState leftHandState = kinectManager.GetLeftHandState(UserID);
            InteractionManager.HandEventType leftHandEvent = InteractionManager.HandStateToEvent(leftHandState, lastLeftHandEvent);

            if(leftHandEvent != InteractionManager.HandEventType.None)
            {
                lastLeftHandEvent = leftHandEvent;
            }
        }

        // get the right hand state and event
        //得到正確的手狀態和事件
        if (kinectManager && kinectManager.GetJointTrackingState(UserID, (int)KinectInterop.JointType.HandRight) != KinectInterop.TrackingState.NotTracked)
        {
            KinectInterop.HandState rightHandState = kinectManager.GetRightHandState(UserID);
            InteractionManager.HandEventType rightHandEvent = InteractionManager.HandStateToEvent(rightHandState, lastRightHandEvent);

            if(rightHandEvent != InteractionManager.HandEventType.None)
            {
                lastRightHandEvent = rightHandEvent;
            }
        }

        // rotate the avatar bones
        //旋轉人物的骨頭
        for (var boneIndex = 0; boneIndex < bones.Length; boneIndex++)
        {
            if (!bones[boneIndex] || isBoneDisabled[boneIndex]) 
                continue;

            if(boneIndex2JointMap.ContainsKey(boneIndex))
            {
                KinectInterop.JointType joint = !(mirroredMovement ^ flipLeftRight) ? 
                    boneIndex2JointMap[boneIndex] : boneIndex2MirrorJointMap[boneIndex];

                if( externalHeadRotation && joint == KinectInterop.JointType.Head)   // skip head if moved externally如果移動到外部,就跳過頭
                {
                    continue;
                }

                TransformBone(UserID, joint, boneIndex, !(mirroredMovement ^ flipLeftRight));
            }
            else if(specIndex2JointMap.ContainsKey(boneIndex))
            {
                // special bones (clavicles)
                //特殊的骨頭(鎖骨)
                List<KinectInterop.JointType> alJoints = !(mirroredMovement ^ flipLeftRight) ? 
                    specIndex2JointMap[boneIndex] : specIndex2MirrorMap[boneIndex];

                if(alJoints.Count >= 2)
                {
                    //Debug.Log(alJoints[0].ToString());
                    Vector3 baseDir = alJoints[0].ToString().EndsWith("Left") ? Vector3.left : Vector3.right;
                    TransformSpecialBone(UserID, alJoints[0], alJoints[1], boneIndex, baseDir, !(mirroredMovement ^ flipLeftRight));
                }
            }
        }

        if (applyMuscleLimits && kinectManager && kinectManager.IsUserTracked(UserID)) 
        {
            // check for limits
            //檢查限制
            CheckMuscleLimits();
        }
    }

    /// <summary>
    /// Resets bones to their initial positions and rotations. This also releases avatar control from KM, by settings playerId to 0 
    /// 將骨頭重新設置爲最初的位置和旋轉。這也會從KM的設置中釋放出阿凡達的控制,將playerId設置爲0
    /// </summary>
    public virtual void ResetToInitialPosition()
    {
        playerId = 0;

        if(bones == null)
            return;

        // For each bone that was defined, reset to initial position.
        //對於每一個被定義的骨頭,重置爲初始位置。
        transform.rotation = Quaternion.identity;

        for(int pass = 0; pass < 2; pass++)  // 2 passes because clavicles are at the end因爲鎖骨在末端
        {
            for(int i = 0; i < bones.Length; i++)
            {
                if(bones[i] != null)
                {
                    bones[i].rotation = initialRotations[i];
                }
            }
        }

        // reset finger bones to initial position
        //將手指骨復位到初始位置
        //Animator animatorComponent = GetComponent<Animator>();
        foreach (HumanBodyBones bone in fingerBoneLocalRotations.Keys)
        {
            Transform boneTransform = animatorComponent ? animatorComponent.GetBoneTransform(bone) : null;

            if(boneTransform)
            {
                boneTransform.localRotation = fingerBoneLocalRotations[bone];
            }
        }

        //      if(bodyRoot != null)
        //      {
        //          bodyRoot.localPosition = Vector3.zero;
        //          bodyRoot.localRotation = Quaternion.identity;
        //      }

        // Restore the offset's position and rotation
        //恢復偏移位置和旋轉
        if (offsetNode != null)
        {
            offsetNode.transform.position = offsetNodePos;
            offsetNode.transform.rotation = offsetNodeRot;
        }

        transform.position = initialPosition;
        transform.rotation = initialRotation;

        if (bones[0]) 
        {
            bones[0].localPosition = initialHipsPosition;
            bones[0].localRotation = initialHipsRotation;
        }
    }

    /// <summary>
    /// Invoked on the successful calibration of the player.
    /// 在玩家成功的校準上被調用。
    /// </summary>
    /// <param name="userId">User identifier.</param>
    public virtual void SuccessfulCalibration(Int64 userId, bool resetInitialTransform)
    {
        playerId = userId;

        // reset the models position
        //重置模型位置
        if(offsetNode != null)
        {
            offsetNode.transform.position = offsetNodePos;
            offsetNode.transform.rotation = offsetNodeRot;
        }

        // reset initial position / rotation if needed 
        //如果需要,重置初始位置/旋轉
        if (resetInitialTransform)
        {
            bodyRootPosition = transform.position;
            initialPosition = transform.position;
            initialRotation = transform.rotation;
        }

        transform.position = initialPosition;
        transform.rotation = initialRotation;

        //      // enable all bones
        //      for(int i = 0; i < bones.Length; i++)
        //      {
        //          isBoneDisabled[i] = false;
        //      }

        // re-calibrate the position offset
        //校準的位置偏移
        offsetCalibrated = false;
    }

    /// <summary>
    /// Moves the avatar to its initial/base position 
    /// 將化身移動到它的初始/基礎位置
    /// </summary>
    /// <param name="position"> world position </param>
    /// <param name="rotation"> rotation offset </param>
    public void resetInitialTransform( Vector3 position, Vector3 rotation )
    {
        bodyRootPosition = position;
        initialPosition = position;
        initialRotation = Quaternion.Euler( rotation );

        transform.position = initialPosition;
        transform.rotation = initialRotation;

        offsetCalibrated = false;       // this cause also calibrating kinect offset in moveAvatar function 這個原因也可以在move化身函數中校正kinect的偏移量
    }

    // Apply the rotations tracked by kinect to the joints.
    //將kinect追蹤的旋轉應用到關節處。
    protected void TransformBone(Int64 userId, KinectInterop.JointType joint, int boneIndex, bool flip)
    {
        Transform boneTransform = bones[boneIndex];
        if(boneTransform == null || kinectManager == null)
            return;

        int iJoint = (int)joint;
        if(iJoint < 0 || !kinectManager.IsJointTracked(userId, iJoint))
            return;

        // Get Kinect joint orientation
        //得到Kinect關節定位
        Quaternion jointRotation = kinectManager.GetJointOrientation(userId, iJoint, flip);
        if(jointRotation == Quaternion.identity)
            return;

        // calculate the new orientation
        //計算的新方向
        Quaternion newRotation = Kinect2AvatarRot(jointRotation, boneIndex);

        if(externalRootMotion)
        {
            newRotation = transform.rotation * newRotation;
        }

        // Smoothly transition to the new rotation
        //平穩過渡到新的旋轉
        if (smoothFactor != 0f)
            boneTransform.rotation = Quaternion.Slerp(boneTransform.rotation, newRotation, smoothFactor * Time.deltaTime);
        else
            boneTransform.rotation = newRotation;
    }

    // Apply the rotations tracked by kinect to a special joint
    //將kinect跟蹤的旋轉應用到一個特殊的關節
    protected void TransformSpecialBone(Int64 userId, KinectInterop.JointType joint, KinectInterop.JointType jointParent, int boneIndex, Vector3 baseDir, bool flip)
    {
        Transform boneTransform = bones[boneIndex];
        if(boneTransform == null || kinectManager == null)
            return;

        if(!kinectManager.IsJointTracked(userId, (int)joint) || 
           !kinectManager.IsJointTracked(userId, (int)jointParent))
        {
            return;
        }

        if(boneIndex >= 27 && boneIndex <= 30)
        {
            // fingers or thumbs
            if(fingerOrientations)
            {
                TransformSpecialBoneFingers(userId, (int)joint, boneIndex, flip);
            }

            return;
        }

        Vector3 jointDir = kinectManager.GetJointDirection(userId, (int)joint, false, true);
        Quaternion jointRotation = jointDir != Vector3.zero ? Quaternion.FromToRotation(baseDir, jointDir) : Quaternion.identity;

        if(!flip)
        {
            Vector3 mirroredAngles = jointRotation.eulerAngles;
            mirroredAngles.y = -mirroredAngles.y;
            mirroredAngles.z = -mirroredAngles.z;

            jointRotation = Quaternion.Euler(mirroredAngles);
        }

        if(jointRotation != Quaternion.identity)
        {
            // Smoothly transition to the new rotation
            //平穩過渡到新的旋轉
            Quaternion newRotation = Kinect2AvatarRot(jointRotation, boneIndex);

            if(externalRootMotion)
            {
                newRotation = transform.rotation * newRotation;
            }

            if(smoothFactor != 0f)
                boneTransform.rotation = Quaternion.Slerp(boneTransform.rotation, newRotation, smoothFactor * Time.deltaTime);
            else
                boneTransform.rotation = newRotation;
        }

    }

    // Apply the rotations tracked by kinect to fingers (one joint = multiple bones)
    //將kinect追蹤的旋轉應用到手指(一個關節=多個骨頭)
    protected void TransformSpecialBoneFingers(Int64 userId, int joint, int boneIndex, bool flip)
    {
        // check for hand grips
        //檢查手握
        if (joint == (int)KinectInterop.JointType.HandTipLeft || joint == (int)KinectInterop.JointType.ThumbLeft)
        {
            if(lastLeftHandEvent == InteractionManager.HandEventType.Grip)
            {
                if(!bLeftFistDone)
                {
                    float angleSign = !mirroredMovement /**(boneIndex == 27 || boneIndex == 29)*/ ? -1f : -1f;
                    float angleRot = angleSign * 60f;

                    TransformSpecialBoneFist(boneIndex, angleRot);
                    bLeftFistDone = (boneIndex >= 29);
                }

                return;
            }
            else if(bLeftFistDone && lastLeftHandEvent == InteractionManager.HandEventType.Release)
            {
                TransformSpecialBoneUnfist(boneIndex);
                bLeftFistDone = !(boneIndex >= 29);
            }
        }
        else if(joint == (int)KinectInterop.JointType.HandTipRight || joint == (int)KinectInterop.JointType.ThumbRight)
        {
            if(lastRightHandEvent == InteractionManager.HandEventType.Grip)
            {
                if(!bRightFistDone)
                {
                    float angleSign = !mirroredMovement /**(boneIndex == 27 || boneIndex == 29)*/ ? -1f : -1f;
                    float angleRot = angleSign * 60f;

                    TransformSpecialBoneFist(boneIndex, angleRot);
                    bRightFistDone = (boneIndex >= 29);
                }

                return;
            }
            else if(bRightFistDone && lastRightHandEvent == InteractionManager.HandEventType.Release)
            {
                TransformSpecialBoneUnfist(boneIndex);
                bRightFistDone = !(boneIndex >= 29);
            }
        }

        // get the animator component
        //Animator animatorComponent = GetComponent<Animator>();
        if(!animatorComponent)
            return;

        // Get Kinect joint orientation
        //得到Kinect聯合定位
        Quaternion jointRotation = kinectManager.GetJointOrientation(userId, joint, flip);
        if(jointRotation == Quaternion.identity)
            return;

        // calculate the new orientation
        //計算的新方向
        Quaternion newRotation = Kinect2AvatarRot(jointRotation, boneIndex);

        if(externalRootMotion)
        {
            newRotation = transform.rotation * newRotation;
        }

        // get the list of bones
        //List<HumanBodyBones> alBones = flip ? specialIndex2MultiBoneMap[boneIndex] : specialIndex2MirrorBoneMap[boneIndex];
        List<HumanBodyBones> alBones = specialIndex2MultiBoneMap[boneIndex];

        // Smoothly transition to the new rotation
        //平穩過渡到新的旋轉
        for (int i = 0; i < alBones.Count; i++)
        {
            Transform boneTransform = animatorComponent.GetBoneTransform(alBones[i]);
            if(!boneTransform)
                continue;

            if(smoothFactor != 0f)
                boneTransform.rotation = Quaternion.Slerp(boneTransform.rotation, newRotation, smoothFactor * Time.deltaTime);
            else
                boneTransform.rotation = newRotation;
        }
    }

    // Apply the rotations needed to transform fingers to fist
    //將手指旋轉到拳頭的轉動
    protected void TransformSpecialBoneFist(int boneIndex, float angle)
    {
        //      // do fist only for fingers
       //       //只做手指
        //      if(boneIndex != 27 && boneIndex != 28)
        //          return;

        // get the animator component
        //Animator animatorComponent = GetComponent<Animator>();
        if (!animatorComponent)
            return;

        // get the list of bones
        List<HumanBodyBones> alBones = specialIndex2MultiBoneMap[boneIndex];

        for(int i = 0; i < alBones.Count; i++)
        {
            if(i < 1 && (boneIndex == 29 || boneIndex == 30))  // skip the first two thumb bones
                continue;

            HumanBodyBones bone = alBones[i];
            Transform boneTransform = animatorComponent.GetBoneTransform(bone);

            // set the fist rotation
            if(boneTransform && fingerBoneLocalAxes[bone] != Vector3.zero)
            {
                Quaternion qRotFinger = Quaternion.AngleAxis(angle, fingerBoneLocalAxes[bone]);
                boneTransform.localRotation = fingerBoneLocalRotations[bone] * qRotFinger;
            }
        }

    }

    // Apply the initial rotations fingers
    //初始旋轉手指
    protected void TransformSpecialBoneUnfist(int boneIndex)
    {
//      // do fist only for fingers
//      if(boneIndex != 27 && boneIndex != 28)
//          return;

        // get the animator component
        //Animator animatorComponent = GetComponent<Animator>();
        if(!animatorComponent)
            return;

        // get the list of bones
        List<HumanBodyBones> alBones = specialIndex2MultiBoneMap[boneIndex];

        for(int i = 0; i < alBones.Count; i++)
        {
            HumanBodyBones bone = alBones[i];
            Transform boneTransform = animatorComponent.GetBoneTransform(bone);

            // set the initial rotation
            if(boneTransform)
            {
                boneTransform.localRotation = fingerBoneLocalRotations[bone];
            }
        }
    }

    // Moves the avatar - gets the tracked position of the user and applies it to avatar.
    //移動化身-獲得用戶的追蹤位置並將其應用到人物。
    protected void MoveAvatar(Int64 UserID)
    {
        if((moveRate == 0f) || !kinectManager ||
           !kinectManager.IsJointTracked(UserID, (int)KinectInterop.JointType.SpineBase))
        {
            return;
        }

        // get the position of user's spine base
        Vector3 trans = kinectManager.GetUserPosition(UserID);
        if(flipLeftRight)
            trans.x = -trans.x;

        // use the color overlay position if needed
        if(posRelativeToCamera && posRelOverlayColor)
        {
            Rect backgroundRect = posRelativeToCamera.pixelRect;
            PortraitBackground portraitBack = PortraitBackground.Instance;

            if(portraitBack && portraitBack.enabled)
            {
                backgroundRect = portraitBack.GetBackgroundRect();
            }

            trans = kinectManager.GetJointPosColorOverlay(UserID, (int)KinectInterop.JointType.SpineBase, posRelativeToCamera, backgroundRect);
            if(flipLeftRight)
                trans.x = -trans.x;
        }

        // invert the z-coordinate, if needed
        //如果需要的話,對z座標求逆
        if (posRelativeToCamera && posRelInvertedZ)
        {
            trans.z = -trans.z;
        }

        if(!offsetCalibrated)
        {
            offsetCalibrated = true;

            offsetPos.x = trans.x;  // !mirroredMovement ? trans.x * moveRate : -trans.x * moveRate;
            offsetPos.y = trans.y;  // trans.y * moveRate;
            offsetPos.z = !mirroredMovement && !posRelativeToCamera ? -trans.z : trans.z;  // -trans.z * moveRate;

            if(posRelativeToCamera)
            {
                Vector3 cameraPos = posRelativeToCamera.transform.position;
                Vector3 bodyRootPos = bodyRoot != null ? bodyRoot.position : transform.position;
                Vector3 hipCenterPos = bodyRoot != null ? bodyRoot.position : (bones != null && bones.Length > 0 && bones[0] != null ? bones[0].position : Vector3.zero);

                float yRelToAvatar = 0f;
                if(verticalMovement)
                {
                    yRelToAvatar = (trans.y - cameraPos.y) - (hipCenterPos - bodyRootPos).magnitude;
                }
                else
                {
                    yRelToAvatar = bodyRootPos.y - cameraPos.y;
                }

                Vector3 relativePos = new Vector3(trans.x, yRelToAvatar, trans.z);
                Vector3 newBodyRootPos = cameraPos + relativePos;

//              if(offsetNode != null)
//              {
//                  newBodyRootPos += offsetNode.transform.position;
//              }

                if(bodyRoot != null)
                {
                    bodyRoot.position = newBodyRootPos;
                }
                else
                {
                    transform.position = newBodyRootPos;
                }

                bodyRootPosition = newBodyRootPos;
            }
        }

        // transition to the new position
        //移動到新的位置
        Vector3 targetPos = bodyRootPosition + Kinect2AvatarPos(trans, verticalMovement);

        if(isRigidBody && !verticalMovement)
        {
            // workaround for obeying the physics (e.g. gravity falling)
            //解決物理問題的方法(如重力下降)
            targetPos.y = bodyRoot != null ? bodyRoot.position.y : transform.position.y;
        }

        if (verticalMovement && verticalOffset != 0f && 
            bones[0] != null && bones[3] != null) 
        {
            Vector3 dirSpine = bones[3].position - bones[0].position;
            targetPos += dirSpine.normalized * verticalOffset;
        }

        if (forwardOffset != 0f && 
            bones[0] != null && bones[3] != null && bones[5] != null && bones[11] != null) 
        {
            Vector3 dirSpine = (bones[3].position - bones[0].position).normalized;
            Vector3 dirShoulders = (bones[11].position - bones[5].position).normalized;
            Vector3 dirForward = Vector3.Cross(dirShoulders, dirSpine).normalized;

            targetPos += dirForward * forwardOffset;
        }

        if(groundedFeet)
        {
            // keep the current correction
            //保持當前的修正
            float fLastTgtY = targetPos.y;
            targetPos.y += fFootDistance;

            float fNewDistance = GetDistanceToGround();
            float fNewDistanceTime = Time.time;

//          Debug.Log(string.Format("PosY: {0:F2}, LastY: {1:F2},  TgrY: {2:F2}, NewDist: {3:F2}, Corr: {4:F2}, Time: {5:F2}", bodyRoot != null ? bodyRoot.position.y : transform.position.y,
//              fLastTgtY, targetPos.y, fNewDistance, fFootDistance, fNewDistanceTime));

            if(Mathf.Abs(fNewDistance) >= 0.01f && Mathf.Abs(fNewDistance - fFootDistanceInitial) >= maxFootDistanceGround)
            {
                if((fNewDistanceTime - fFootDistanceTime) >= maxFootDistanceTime)
                {
                    fFootDistance += (fNewDistance - fFootDistanceInitial);
                    fFootDistanceTime = fNewDistanceTime;

                    targetPos.y = fLastTgtY + fFootDistance;

//                  Debug.Log(string.Format("   >> change({0:F2})! - Corr: {1:F2}, LastY: {2:F2},  TgrY: {3:F2} at time {4:F2}", 
//                              (fNewDistance - fFootDistanceInitial), fFootDistance, fLastTgtY, targetPos.y, fFootDistanceTime));
                }
            }
            else
            {
                fFootDistanceTime = fNewDistanceTime;
            }
        }

        if(bodyRoot != null)
        {
            bodyRoot.position = smoothFactor != 0f ? 
                Vector3.Lerp(bodyRoot.position, targetPos, smoothFactor * Time.deltaTime) : targetPos;
        }
        else
        {
            transform.position = smoothFactor != 0f ? 
                Vector3.Lerp(transform.position, targetPos, smoothFactor * Time.deltaTime) : targetPos;
        }
    }

    // Set model's arms to be in T-pose
    //將模型的手臂放在t形上
    protected void SetModelArmsInTpose()
    {
        Vector3 vTposeLeftDir = transform.TransformDirection(Vector3.left);
        Vector3 vTposeRightDir = transform.TransformDirection(Vector3.right);

        Transform transLeftUarm = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.ShoulderLeft, false)); // animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
        Transform transLeftLarm = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.ElbowLeft, false)); // animator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
        Transform transLeftHand = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.WristLeft, false)); // animator.GetBoneTransform(HumanBodyBones.LeftHand);

        if(transLeftUarm != null && transLeftLarm != null)
        {
            Vector3 vUarmLeftDir = transLeftLarm.position - transLeftUarm.position;
            float fUarmLeftAngle = Vector3.Angle(vUarmLeftDir, vTposeLeftDir);

            if(Mathf.Abs(fUarmLeftAngle) >= 5f)
            {
                Quaternion vFixRotation = Quaternion.FromToRotation(vUarmLeftDir, vTposeLeftDir);
                transLeftUarm.rotation = vFixRotation * transLeftUarm.rotation;
            }

            if(transLeftHand != null)
            {
                Vector3 vLarmLeftDir = transLeftHand.position - transLeftLarm.position;
                float fLarmLeftAngle = Vector3.Angle(vLarmLeftDir, vTposeLeftDir);

                if(Mathf.Abs(fLarmLeftAngle) >= 5f)
                {
                    Quaternion vFixRotation = Quaternion.FromToRotation(vLarmLeftDir, vTposeLeftDir);
                    transLeftLarm.rotation = vFixRotation * transLeftLarm.rotation;
                }
            }
        }

        Transform transRightUarm = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.ShoulderRight, false)); // animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
        Transform transRightLarm = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.ElbowRight, false)); // animator.GetBoneTransform(HumanBodyBones.RightLowerArm);
        Transform transRightHand = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.WristRight, false)); // animator.GetBoneTransform(HumanBodyBones.RightHand);

        if(transRightUarm != null && transRightLarm != null)
        {
            Vector3 vUarmRightDir = transRightLarm.position - transRightUarm.position;
            float fUarmRightAngle = Vector3.Angle(vUarmRightDir, vTposeRightDir);

            if(Mathf.Abs(fUarmRightAngle) >= 5f)
            {
                Quaternion vFixRotation = Quaternion.FromToRotation(vUarmRightDir, vTposeRightDir);
                transRightUarm.rotation = vFixRotation * transRightUarm.rotation;
            }

            if(transRightHand != null)
            {
                Vector3 vLarmRightDir = transRightHand.position - transRightLarm.position;
                float fLarmRightAngle = Vector3.Angle(vLarmRightDir, vTposeRightDir);

                if(Mathf.Abs(fLarmRightAngle) >= 5f)
                {
                    Quaternion vFixRotation = Quaternion.FromToRotation(vLarmRightDir, vTposeRightDir);
                    transRightLarm.rotation = vFixRotation * transRightLarm.rotation;
                }
            }
        }

    }

    // If the bones to be mapped have been declared, map that bone to the model.
    //如果要映射的骨頭已經被聲明瞭,那就把骨頭映射到模型上。
    protected virtual void MapBones()
    {
//      // make OffsetNode as a parent of model transform.
//      offsetNode = new GameObject(name + "Ctrl") { layer = transform.gameObject.layer, tag = transform.gameObject.tag };
//      offsetNode.transform.position = transform.position;
//      offsetNode.transform.rotation = transform.rotation;
//      offsetNode.transform.parent = transform.parent;

//      // take model transform as body root
//      transform.parent = offsetNode.transform;
//      transform.localPosition = Vector3.zero;
//      transform.localRotation = Quaternion.identity;

        //bodyRoot = transform;

        // get bone transforms from the animator component
        //Animator animatorComponent = GetComponent<Animator>();

        for (int boneIndex = 0; boneIndex < bones.Length; boneIndex++)
        {
            if (!boneIndex2MecanimMap.ContainsKey(boneIndex)) 
                continue;

            bones[boneIndex] = animatorComponent ? animatorComponent.GetBoneTransform(boneIndex2MecanimMap[boneIndex]) : null;
        }
    }

    // Capture the initial rotations of the bones
    protected void GetInitialRotations()
    {
        // save the initial rotation
        if(offsetNode != null)
        {
            offsetNodePos = offsetNode.transform.position;
            offsetNodeRot = offsetNode.transform.rotation;
        }

        initialPosition = transform.position;
        initialRotation = transform.rotation;

        initialHipsPosition = bones[0] ? bones[0].localPosition : Vector3.zero;
        initialHipsRotation = bones[0] ? bones[0].localRotation : Quaternion.identity;

//      if(offsetNode != null)
//      {
//          initialRotation = Quaternion.Inverse(offsetNodeRot) * initialRotation;
//      }

        transform.rotation = Quaternion.identity;

        // save the body root initial position
        if(bodyRoot != null)
        {
            bodyRootPosition = bodyRoot.position;
        }
        else
        {
            bodyRootPosition = transform.position;
        }

        if(offsetNode != null)
        {
            bodyRootPosition = bodyRootPosition - offsetNodePos;
        }

        // save the initial bone rotations
        for (int i = 0; i < bones.Length; i++)
        {
            if (bones[i] != null)
            {
                initialRotations[i] = bones[i].rotation;
                localRotations[i] = bones[i].localRotation;
            }
        }

        // get finger bones' local rotations
        //Animator animatorComponent = GetComponent<Animator>();
        foreach(int boneIndex in specialIndex2MultiBoneMap.Keys)
        {
            List<HumanBodyBones> alBones = specialIndex2MultiBoneMap[boneIndex];
            //Transform handTransform = animatorComponent.GetBoneTransform((boneIndex == 27 || boneIndex == 29) ? HumanBodyBones.LeftHand : HumanBodyBones.RightHand);

            for(int b = 0; b < alBones.Count; b++)
            {
                HumanBodyBones bone = alBones[b];
                Transform boneTransform = animatorComponent ? animatorComponent.GetBoneTransform(bone) : null;

                // get the finger's 1st transform
                Transform fingerBaseTransform = animatorComponent ? animatorComponent.GetBoneTransform(alBones[b - (b % 3)]) : null;
                //Vector3 vBoneDirParent = handTransform && fingerBaseTransform ? (handTransform.position - fingerBaseTransform.position).normalized : Vector3.zero;

                // get the finger's 2nd transform
                Transform baseChildTransform = fingerBaseTransform && fingerBaseTransform.childCount > 0 ? fingerBaseTransform.GetChild(0) : null;
                Vector3 vBoneDirChild = baseChildTransform && fingerBaseTransform ? (baseChildTransform.position - fingerBaseTransform.position).normalized : Vector3.zero;
                Vector3 vOrthoDirChild = Vector3.Cross(vBoneDirChild, Vector3.up).normalized;

                if(boneTransform)
                {
                    fingerBoneLocalRotations[bone] = boneTransform.localRotation;

                    if (vBoneDirChild != Vector3.zero) 
                    {
                        fingerBoneLocalAxes[bone] = boneTransform.InverseTransformDirection(vOrthoDirChild).normalized;
                    } 
                    else 
                    {
                        fingerBoneLocalAxes [bone] = Vector3.zero;
                    }

//                  Transform bparTransform = boneTransform ? boneTransform.parent : null;
//                  Transform bchildTransform = boneTransform && boneTransform.childCount > 0 ? boneTransform.GetChild(0) : null;
//
//                  // get the finger base transform (1st joint)
//                  Transform fingerBaseTransform = animatorComponent.GetBoneTransform(alBones[b - (b % 3)]);
//                  Vector3 vBoneDir2 = (handTransform.position - fingerBaseTransform.position).normalized;
//
//                  // set the fist rotation
//                  if(boneTransform && fingerBaseTransform && handTransform)
//                  {
//                      Vector3 vBoneDir = bchildTransform ? (bchildTransform.position - boneTransform.position).normalized :
//                          (bparTransform ? (boneTransform.position - bparTransform.position).normalized : Vector3.zero);
//
//                      Vector3 vOrthoDir = Vector3.Cross(vBoneDir2, vBoneDir).normalized;
//                      fingerBoneLocalAxes[bone] = boneTransform.InverseTransformDirection(vOrthoDir);
//                  }
                }
            }
        }

        // Restore the initial rotation
        transform.rotation = initialRotation;
    }

    // Converts kinect joint rotation to avatar joint rotation, depending on joint initial rotation and offset rotation
    protected Quaternion Kinect2AvatarRot(Quaternion jointRotation, int boneIndex)
    {
        Quaternion newRotation = jointRotation * initialRotations[boneIndex];
        //newRotation = initialRotation * newRotation;

//      if(offsetNode != null)
//      {
//          newRotation = offsetNode.transform.rotation * newRotation;
//      }
//      else
        {
            newRotation = initialRotation * newRotation;
        }

        return newRotation;
    }

    // Converts Kinect position to avatar skeleton position, depending on initial position, mirroring and move rate
    protected Vector3 Kinect2AvatarPos(Vector3 jointPosition, bool bMoveVertically)
    {
        float xPos = (jointPosition.x - offsetPos.x) * moveRate;
        float yPos = (jointPosition.y - offsetPos.y) * moveRate;
        float zPos = !mirroredMovement && !posRelativeToCamera ? (-jointPosition.z - offsetPos.z) * moveRate : (jointPosition.z - offsetPos.z) * moveRate;

        Vector3 newPosition = new Vector3(xPos, bMoveVertically ? yPos : 0f, zPos);

        Quaternion posRotation = mirroredMovement ? Quaternion.Euler (0f, 180f, 0f) * initialRotation : initialRotation;
        newPosition = posRotation * newPosition;

        if(offsetNode != null)
        {
            //newPosition += offsetNode.transform.position;
            newPosition = offsetNode.transform.position;
        }

        return newPosition;
    }

    // returns distance from the given transform to the underlying object. The player must be in IgnoreRaycast layer.
    //返回從給定轉換到底層對象的距離。玩家必須在無知的層中。
    protected virtual float GetTransformDistanceToGround(Transform trans)
    {
        if(!trans)
            return 0f;

//      RaycastHit hit;
//      if(Physics.Raycast(trans.position, Vector3.down, out hit, 2f, raycastLayers))
//      {
//          return -hit.distance;
//      }
//      else if(Physics.Raycast(trans.position, Vector3.up, out hit, 2f, raycastLayers))
//      {
//          return hit.distance;
//      }
//      else
//      {
//          if (trans.position.y < 0)
//              return -trans.position.y;
//          else
//              return 1000f;
//      }

        return -trans.position.y;
    }

    // returns the lower distance distance from left or right foot to the ground, or 1000f if no LF/RF transforms are found
    //如果沒有發現f/rf變換,則返回從左或右到地面的較低距離距離,或1000 f。
    protected virtual float GetDistanceToGround()
    {
        if(leftFoot == null && rightFoot == null)
        {
//          Animator animatorComponent = GetComponent<Animator>();
//
//          if(animatorComponent)
//          {
//              leftFoot = animatorComponent.GetBoneTransform(HumanBodyBones.LeftFoot);
//              rightFoot = animatorComponent.GetBoneTransform(HumanBodyBones.RightFoot);
//          }

            leftFoot = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.FootLeft, false));
            rightFoot = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.FootRight, false));

            if (leftFoot == null || rightFoot == null) 
            {
                leftFoot = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.AnkleLeft, false));
                rightFoot = GetBoneTransform(GetBoneIndexByJoint(KinectInterop.JointType.AnkleRight, false));
            }
        }

        float fDistMin = 1000f;
        float fDistLeft = leftFoot ? GetTransformDistanceToGround(leftFoot) : fDistMin;
        float fDistRight = rightFoot ? GetTransformDistanceToGround(rightFoot) : fDistMin;
        fDistMin = Mathf.Abs(fDistLeft) < Mathf.Abs(fDistRight) ? fDistLeft : fDistRight;

        if(fDistMin == 1000f)
        {
            fDistMin = 0f; // fFootDistanceInitial;
        }

//      Debug.Log (string.Format ("LFootY: {0:F2}, Dist: {1:F2}, RFootY: {2:F2}, Dist: {3:F2}, Min: {4:F2}", leftFoot ? leftFoot.position.y : 0f, fDistLeft,
//                      rightFoot ? rightFoot.position.y : 0f, fDistRight, fDistMin));

        return fDistMin;
    }

//  protected void OnCollisionEnter(Collision col)
//  {
//      Debug.Log("Collision entered");
//  }
//
//  protected void OnCollisionExit(Collision col)
//  {
//      Debug.Log("Collision exited");
//  }

    // dictionaries to speed up bones' processing
    // the author of the terrific idea for kinect-joints to mecanim-bones mapping
    // along with its initial implementation, including following dictionary is
    // Mikhail Korchun ([email protected]). Big thanks to this guy!
    //字典加速骨的處理
//他是關於關節-骨映射的極好方法的作者
//連同它的初始實現,包括以下字典
//米哈伊爾Korchun(korchoon @gmail.com)。感謝這個傢伙!
    protected static readonly Dictionary<int, HumanBodyBones> boneIndex2MecanimMap = new Dictionary<int, HumanBodyBones>
    {
        {0, HumanBodyBones.Hips},
        {1, HumanBodyBones.Spine},
//        {2, HumanBodyBones.Chest},
        {3, HumanBodyBones.Neck},
//      {4, HumanBodyBones.Head},

        {5, HumanBodyBones.LeftUpperArm},
        {6, HumanBodyBones.LeftLowerArm},
        {7, HumanBodyBones.LeftHand},
//      {8, HumanBodyBones.LeftIndexProximal},
//      {9, HumanBodyBones.LeftIndexIntermediate},
//      {10, HumanBodyBones.LeftThumbProximal},

        {11, HumanBodyBones.RightUpperArm},
        {12, HumanBodyBones.RightLowerArm},
        {13, HumanBodyBones.RightHand},
//      {14, HumanBodyBones.RightIndexProximal},
//      {15, HumanBodyBones.RightIndexIntermediate},
//      {16, HumanBodyBones.RightThumbProximal},

        {17, HumanBodyBones.LeftUpperLeg},
        {18, HumanBodyBones.LeftLowerLeg},
        {19, HumanBodyBones.LeftFoot},
//      {20, HumanBodyBones.LeftToes},

        {21, HumanBodyBones.RightUpperLeg},
        {22, HumanBodyBones.RightLowerLeg},
        {23, HumanBodyBones.RightFoot},
//      {24, HumanBodyBones.RightToes},

        {25, HumanBodyBones.LeftShoulder},
        {26, HumanBodyBones.RightShoulder},
        {27, HumanBodyBones.LeftIndexProximal},
        {28, HumanBodyBones.RightIndexProximal},
        {29, HumanBodyBones.LeftThumbProximal},
        {30, HumanBodyBones.RightThumbProximal},
    };

    protected static readonly Dictionary<int, KinectInterop.JointType> boneIndex2JointMap = new Dictionary<int, KinectInterop.JointType>
    {
        {0, KinectInterop.JointType.SpineBase},
        {1, KinectInterop.JointType.SpineMid},
        {2, KinectInterop.JointType.SpineShoulder},
        {3, KinectInterop.JointType.Neck},
        {4, KinectInterop.JointType.Head},

        {5, KinectInterop.JointType.ShoulderLeft},
        {6, KinectInterop.JointType.ElbowLeft},
        {7, KinectInterop.JointType.WristLeft},
        {8, KinectInterop.JointType.HandLeft},

        {9, KinectInterop.JointType.HandTipLeft},
        {10, KinectInterop.JointType.ThumbLeft},

        {11, KinectInterop.JointType.ShoulderRight},
        {12, KinectInterop.JointType.ElbowRight},
        {13, KinectInterop.JointType.WristRight},
        {14, KinectInterop.JointType.HandRight},

        {15, KinectInterop.JointType.HandTipRight},
        {16, KinectInterop.JointType.ThumbRight},

        {17, KinectInterop.JointType.HipLeft},
        {18, KinectInterop.JointType.KneeLeft},
        {19, KinectInterop.JointType.AnkleLeft},
        {20, KinectInterop.JointType.FootLeft},

        {21, KinectInterop.JointType.HipRight},
        {22, KinectInterop.JointType.KneeRight},
        {23, KinectInterop.JointType.AnkleRight},
        {24, KinectInterop.JointType.FootRight},
    };

    protected static readonly Dictionary<int, List<KinectInterop.JointType>> specIndex2JointMap = new Dictionary<int, List<KinectInterop.JointType>>
    {
        {25, new List<KinectInterop.JointType> {KinectInterop.JointType.ShoulderLeft, KinectInterop.JointType.SpineShoulder} },
        {26, new List<KinectInterop.JointType> {KinectInterop.JointType.ShoulderRight, KinectInterop.JointType.SpineShoulder} },
        {27, new List<KinectInterop.JointType> {KinectInterop.JointType.HandTipLeft, KinectInterop.JointType.HandLeft} },
        {28, new List<KinectInterop.JointType> {KinectInterop.JointType.HandTipRight, KinectInterop.JointType.HandRight} },
        {29, new List<KinectInterop.JointType> {KinectInterop.JointType.ThumbLeft, KinectInterop.JointType.HandLeft} },
        {30, new List<KinectInterop.JointType> {KinectInterop.JointType.ThumbRight, KinectInterop.JointType.HandRight} },
    };

    protected static readonly Dictionary<int, KinectInterop.JointType> boneIndex2MirrorJointMap = new Dictionary<int, KinectInterop.JointType>
    {
        {0, KinectInterop.JointType.SpineBase},
        {1, KinectInterop.JointType.SpineMid},
        {2, KinectInterop.JointType.SpineShoulder},
        {3, KinectInterop.JointType.Neck},
        {4, KinectInterop.JointType.Head},

        {5, KinectInterop.JointType.ShoulderRight},
        {6, KinectInterop.JointType.ElbowRight},
        {7, KinectInterop.JointType.WristRight},
        {8, KinectInterop.JointType.HandRight},

        {9, KinectInterop.JointType.HandTipRight},
        {10, KinectInterop.JointType.ThumbRight},

        {11, KinectInterop.JointType.ShoulderLeft},
        {12, KinectInterop.JointType.ElbowLeft},
        {13, KinectInterop.JointType.WristLeft},
        {14, KinectInterop.JointType.HandLeft},

        {15, KinectInterop.JointType.HandTipLeft},
        {16, KinectInterop.JointType.ThumbLeft},

        {17, KinectInterop.JointType.HipRight},
        {18, KinectInterop.JointType.KneeRight},
        {19, KinectInterop.JointType.AnkleRight},
        {20, KinectInterop.JointType.FootRight},

        {21, KinectInterop.JointType.HipLeft},
        {22, KinectInterop.JointType.KneeLeft},
        {23, KinectInterop.JointType.AnkleLeft},
        {24, KinectInterop.JointType.FootLeft},
    };

    protected static readonly Dictionary<int, List<KinectInterop.JointType>> specIndex2MirrorMap = new Dictionary<int, List<KinectInterop.JointType>>
    {
        {25, new List<KinectInterop.JointType> {KinectInterop.JointType.ShoulderRight, KinectInterop.JointType.SpineShoulder} },
        {26, new List<KinectInterop.JointType> {KinectInterop.JointType.ShoulderLeft, KinectInterop.JointType.SpineShoulder} },
        {27, new List<KinectInterop.JointType> {KinectInterop.JointType.HandTipRight, KinectInterop.JointType.HandRight} },
        {28, new List<KinectInterop.JointType> {KinectInterop.JointType.HandTipLeft, KinectInterop.JointType.HandLeft} },
        {29, new List<KinectInterop.JointType> {KinectInterop.JointType.ThumbRight, KinectInterop.JointType.HandRight} },
        {30, new List<KinectInterop.JointType> {KinectInterop.JointType.ThumbLeft, KinectInterop.JointType.HandLeft} },
    };

    protected static readonly Dictionary<KinectInterop.JointType, int> jointMap2boneIndex = new Dictionary<KinectInterop.JointType, int>
    {
        {KinectInterop.JointType.SpineBase, 0},
        {KinectInterop.JointType.SpineMid, 1},
        {KinectInterop.JointType.SpineShoulder, 2},
        {KinectInterop.JointType.Neck, 3},
        {KinectInterop.JointType.Head, 4},

        {KinectInterop.JointType.ShoulderLeft, 5},
        {KinectInterop.JointType.ElbowLeft, 6},
        {KinectInterop.JointType.WristLeft, 7},
        {KinectInterop.JointType.HandLeft, 8},

        {KinectInterop.JointType.HandTipLeft, 9},
        {KinectInterop.JointType.ThumbLeft, 10},

        {KinectInterop.JointType.ShoulderRight, 11},
        {KinectInterop.JointType.ElbowRight, 12},
        {KinectInterop.JointType.WristRight, 13},
        {KinectInterop.JointType.HandRight, 14},

        {KinectInterop.JointType.HandTipRight, 15},
        {KinectInterop.JointType.ThumbRight, 16},

        {KinectInterop.JointType.HipLeft, 17},
        {KinectInterop.JointType.KneeLeft, 18},
        {KinectInterop.JointType.AnkleLeft, 19},
        {KinectInterop.JointType.FootLeft, 20},

        {KinectInterop.JointType.HipRight, 21},
        {KinectInterop.JointType.KneeRight, 22},
        {KinectInterop.JointType.AnkleRight, 23},
        {KinectInterop.JointType.FootRight, 24},
    };

    protected static readonly Dictionary<KinectInterop.JointType, int> mirrorJointMap2boneIndex = new Dictionary<KinectInterop.JointType, int>
    {
        {KinectInterop.JointType.SpineBase, 0},
        {KinectInterop.JointType.SpineMid, 1},
        {KinectInterop.JointType.SpineShoulder, 2},
        {KinectInterop.JointType.Neck, 3},
        {KinectInterop.JointType.Head, 4},

        {KinectInterop.JointType.ShoulderRight, 5},
        {KinectInterop.JointType.ElbowRight, 6},
        {KinectInterop.JointType.WristRight, 7},
        {KinectInterop.JointType.HandRight, 8},

        {KinectInterop.JointType.HandTipRight, 9},
        {KinectInterop.JointType.ThumbRight, 10},

        {KinectInterop.JointType.ShoulderLeft, 11},
        {KinectInterop.JointType.ElbowLeft, 12},
        {KinectInterop.JointType.WristLeft, 13},
        {KinectInterop.JointType.HandLeft, 14},

        {KinectInterop.JointType.HandTipLeft, 15},
        {KinectInterop.JointType.ThumbLeft, 16},

        {KinectInterop.JointType.HipRight, 17},
        {KinectInterop.JointType.KneeRight, 18},
        {KinectInterop.JointType.AnkleRight, 19},
        {KinectInterop.JointType.FootRight, 20},

        {KinectInterop.JointType.HipLeft, 21},
        {KinectInterop.JointType.KneeLeft, 22},
        {KinectInterop.JointType.AnkleLeft, 23},
        {KinectInterop.JointType.FootLeft, 24},
    };


    protected static readonly Dictionary<int, List<HumanBodyBones>> specialIndex2MultiBoneMap = new Dictionary<int, List<HumanBodyBones>>
    {
        {27, new List<HumanBodyBones> {  // left fingers
                HumanBodyBones.LeftIndexProximal,
                HumanBodyBones.LeftIndexIntermediate,
                HumanBodyBones.LeftIndexDistal,
                HumanBodyBones.LeftMiddleProximal,
                HumanBodyBones.LeftMiddleIntermediate,
                HumanBodyBones.LeftMiddleDistal,
                HumanBodyBones.LeftRingProximal,
                HumanBodyBones.LeftRingIntermediate,
                HumanBodyBones.LeftRingDistal,
                HumanBodyBones.LeftLittleProximal,
                HumanBodyBones.LeftLittleIntermediate,
                HumanBodyBones.LeftLittleDistal,
            }},
        {28, new List<HumanBodyBones> {  // right fingers
                HumanBodyBones.RightIndexProximal,
                HumanBodyBones.RightIndexIntermediate,
                HumanBodyBones.RightIndexDistal,
                HumanBodyBones.RightMiddleProximal,
                HumanBodyBones.RightMiddleIntermediate,
                HumanBodyBones.RightMiddleDistal,
                HumanBodyBones.RightRingProximal,
                HumanBodyBones.RightRingIntermediate,
                HumanBodyBones.RightRingDistal,
                HumanBodyBones.RightLittleProximal,
                HumanBodyBones.RightLittleIntermediate,
                HumanBodyBones.RightLittleDistal,
            }},
        {29, new List<HumanBodyBones> {  // left thumb
                HumanBodyBones.LeftThumbProximal,
                HumanBodyBones.LeftThumbIntermediate,
                HumanBodyBones.LeftThumbDistal,
            }},
        {30, new List<HumanBodyBones> {  // right thumb
                HumanBodyBones.RightThumbProximal,
                HumanBodyBones.RightThumbIntermediate,
                HumanBodyBones.RightThumbDistal,
            }},
    };

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章