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 (korchoon@gmail.com). 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,
}},
};
}