using UnityEngine; //using Windows.Kinect; using System; using System.Collections; using System.Collections.Generic; using com.rfilkov.kinect; namespace com.rfilkov.components { /// /// Avatar controller is the component that transfers the captured user motion to a humanoid model (avatar). /// [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 = true; [Tooltip("Whether the avatar is allowed to move horizontally or not.")] public bool horizontalMovement = true; [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).")] public bool externalHeadRotation = false; [Tooltip("Whether the hand and finger rotations are controlled externally (e.g. by LeapMotion controller)")] public bool externalHandRotations = 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("Whether to update the avatar in LateUpdate(), instead of in Update(). Needed for Mecanim animation blending.")] public bool lateUpdateAvatar = false; [Tooltip("Game object this transform is relative to (optional).")] public Transform 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("Plane used to render the color camera background to overlay.")] //public Transform backgroundPlane; [Tooltip("Whether z-axis movement needs to be inverted (Pos-Relative mode only).")] [HideInInspector] 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 model's muscle limits or not.")] public bool applyMuscleLimits = false; [Tooltip("Whether to flip left and right, relative to the sensor.")] public bool flipLeftRight = false; [Tooltip("Horizontal offset of the avatar with respect to the position of user's spine-base.")] [Range(-0.5f, 0.5f)] public float horizontalOffset = 0f; [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 offset of the avatar with respect to the position of user's spine-base.")] [Range(-0.5f, 0.5f)] public float forwardOffset = 0f; // suggested and implemented by Ruben Gonzalez [Tooltip("Whether to use unscaled or normal (scaled) time.")] public bool useUnscaledTime = false; [Tooltip("Radius of the joint sphere and bone capsule colliders, in meters. You can set it to 0.02 to try it out. 0 means no collider.")] [Range(0f, 0.1f)] public float boneColliderRadius = 0f; // 0.02f; // userId of the player [NonSerialized] public ulong playerId = 0; // The body root node protected Transform bodyRoot; protected float hipCenterDist = 0f; // Variable to hold all them bones. It will initialize the same size as initialRotations. protected Transform[] bones; //protected Transform[] fingerBones; protected CapsuleCollider[] boneColliders; protected Transform[] boneColTrans; protected Transform[] boneColJoint; protected Transform[] boneColParent; // Rotations of the bones when the Kinect tracking starts. protected Quaternion[] initialRotations; protected Quaternion[] localRotations; protected bool[] isBoneDisabled; // Local rotations of finger bones protected Dictionary fingerBoneLocalRotations = new Dictionary(); protected Dictionary fingerBoneLocalAxes = new Dictionary(); // Initial position and rotation of the transform protected Vector3 initialPosition; protected Quaternion initialRotation; protected Vector3 initialHipsPosition; protected Quaternion initialHipsRotation; protected Vector3 initialUpVector; //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; //protected Vector3 offsetCamPos = Vector3.zero; //protected Quaternion offsetCamRot = Quaternion.identity; // whether the user pose has been applied on the avatar or not protected bool poseApplied = false; protected Quaternion pelvisRotation = Quaternion.identity; // sharp rotation angle protected const float SHARP_ROT_ANGLE = 90f; // 90 degrees protected 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 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 //protected const int raycastLayers = ~2; // Ignore Raycast protected const float MaxFootDistanceGround = 0.02f; // maximum distance from lower foot to the ground protected const float MaxFootDistanceTime = 0.2f; // 1.0f; // maximum allowed time, the lower foot to be distant from the ground protected Transform leftFoot, rightFoot; protected Vector3 leftFootPos, rightFootPos; //protected float fFootDistanceInitial = 0f; protected float fFootDistance = 0f; protected float fFootDistanceTime = 0f; protected Vector3 vFootCorrection = Vector3.zero; //// background plane rectangle //private Rect planeRect = new Rect(); //private bool planeRectSet = false; // last time when the avatar was updated protected float lastUpdateTime = 0f; protected const float MaxUpdateTime = 0.5f; // allow 0.5 seconds max for smooth updates /// /// Gets the number of bone transforms (array length). /// /// The number of bone transforms. public int GetBoneTransformCount() { return bones != null ? bones.Length : 0; } /// /// Gets the bone transform by index. /// /// The bone transform. /// Index public Transform GetBoneTransform(int index) { if (index >= 0 && bones != null && index < bones.Length) { return bones[index]; } return null; } /// /// Disables the bone and optionally resets its orientation. /// /// Bone index. /// If set to true resets bone orientation. 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]; } } } /// /// Enables the bone, so AvatarController could update its orientation. /// /// Bone index. public void EnableBone(int index) { if (index >= 0 && index < bones.Length) { isBoneDisabled[index] = false; } } /// /// Determines whether the bone orientation update is enabled or not. /// /// true if the bone update is enabled; otherwise, false. /// Bone index. public bool IsBoneEnabled(int index) { if (index >= 0 && index < bones.Length) { return !isBoneDisabled[index]; } return false; } /// /// Gets the bone index by joint type. /// /// The bone index. /// Joint type /// If set to true gets the mirrored joint index. public int GetBoneIndexByJoint(KinectInterop.JointType joint, bool bMirrored) { int boneIndex = -1; if (jointMap2boneIndex.ContainsKey(joint)) { boneIndex = !bMirrored ? jointMap2boneIndex[joint] : mirrorJointMap2boneIndex[joint]; } return boneIndex; } /// /// Gets the list of AC-controlled mecanim bones. /// /// List of AC-controlled mecanim bones public List GetMecanimBones() { List alMecanimBones = new List(); for (int boneIndex = 0; boneIndex < bones.Length; boneIndex++) { if (!boneIndex2MecanimMap.ContainsKey(boneIndex) || boneIndex >= 21) continue; alMecanimBones.Add(boneIndex2MecanimMap[boneIndex]); } return alMecanimBones; } // transform caching gives performance boost since Unity calls GetComponent() each time you call transform private Transform _transformCache; public new Transform transform { get { if (!_transformCache) { _transformCache = base.transform; } return _transformCache; } } public virtual void Awake() { // check for double start if (bones != null) return; if (!gameObject.activeInHierarchy) return; // inits the bones array bones = new Transform[25]; // get the animator reference animatorComponent = GetComponent(); // Map bones to the points the Kinect tracks MapBones(); // get distance to hip center 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 : transform.position); hipCenterDist = (hipCenterPos - bodyRootPos).magnitude; // Set model's arms to be in T-pose, if needed 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 = GetCorrDistanceToGround(); fFootDistance = 0f; fFootDistanceTime = 0f; // get left & right foot positions 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)); } leftFootPos = leftFoot != null ? leftFoot.position : Vector3.zero; rightFootPos = rightFoot != null ? rightFoot.position : Vector3.zero; // if parent transform uses physics isRigidBody = (gameObject.GetComponent() != null); // get the pose handler reference if (animatorComponent && animatorComponent.avatar && animatorComponent.avatar.isHuman) { Transform hipsTransform = animatorComponent.GetBoneTransform(HumanBodyBones.Hips); Transform rootTransform = hipsTransform; // transform; humanPoseHandler = new HumanPoseHandler(animatorComponent.avatar, rootTransform); humanPoseHandler.GetHumanPose(ref humanPose); initialHipsPosition = (humanPose.bodyPosition - rootTransform.position); // hipsTransform.position initialHipsRotation = humanPose.bodyRotation; //Debug.Log($"{gameObject.name} - initialHipsPos: {initialHipsPosition}, rot: {initialHipsRotation.eulerAngles}, humanPosePos: {humanPose.bodyPosition}, transformPos: {rootTransform.position}"); } // create bone and joint colliders, if needed CreateBoneColliders(); } public virtual void Update() { if(kinectManager == null) { kinectManager = KinectManager.Instance; } ulong userId = kinectManager ? kinectManager.GetUserIdByIndex(playerIndex) : 0; if (playerId != userId) { if (/**playerId == 0 &&*/ userId != 0) SuccessfulCalibration(userId, false); else if (/**playerId != 0 &&*/ userId == 0) ResetToInitialPosition(); } if (!lateUpdateAvatar && playerId != 0) { //Vector3 playerPos = kinectManager.GetUserPosition(playerId); //Vector3 playerRot = kinectManager.GetJointOrientation(playerId, 0, true).eulerAngles; //Debug.Log(string.Format("Avatar userIndex: {0}, userId: {1}, pos: {2}, rot: {3}", playerIndex, playerId, playerPos, playerRot)); UpdateAvatar(playerId); } } public virtual void LateUpdate() { if (lateUpdateAvatar && playerId != 0) { UpdateAvatar(playerId); } // update bone colliders, as needed UpdateBoneColliders(); } // 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; Vector3 localBodyPos = Quaternion.Inverse(initialHipsRotation) * initialHipsPosition; Quaternion localBodyRot = Quaternion.Inverse(initialHipsRotation) * humanPose.bodyRotation; //Debug.Log($"{gameObject.name} - lBodyPos: {localBodyPos}, lBodyRot: {localBodyRot.eulerAngles}\ninitHipsPos: {initialHipsPosition}, initHipsRot: {initialHipsRotation.eulerAngles}"); // recover the body position & orientation humanPose.bodyPosition = localBodyPos; // initialHipsPosition; humanPose.bodyRotation = localBodyRot; // Quaternion.identity; humanPoseHandler.SetHumanPose(ref humanPose); //Debug.Log(" Human pose updated."); } } /// /// Updates the avatar each frame. /// /// User ID public virtual void UpdateAvatar(ulong UserID) { if (!gameObject.activeInHierarchy) return; // Get the KinectManager instance if (kinectManager == null) { kinectManager = KinectManager.Instance; } //// get the background plane rectangle if needed //if (backgroundPlane && !planeRectSet && kinectManager && kinectManager.IsInitialized()) //{ // planeRectSet = true; // planeRect.width = 10f * Mathf.Abs(backgroundPlane.localScale.x); // planeRect.height = 10f * Mathf.Abs(backgroundPlane.localScale.z); // planeRect.x = backgroundPlane.position.x - planeRect.width / 2f; // planeRect.y = backgroundPlane.position.y - planeRect.height / 2f; //} // move the avatar to its Kinect position 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; // } //} // check for sharp pelvis rotations float pelvisAngle = GetPelvisAngle(UserID, false); if (!poseApplied || pelvisAngle < SHARP_ROT_ANGLE) { // rotate the avatar bones for (var boneIndex = 0; boneIndex < bones.Length; boneIndex++) { if (!bones[boneIndex] || isBoneDisabled[boneIndex]) // check for missing or disabled bones continue; bool flip = !(mirroredMovement ^ flipLeftRight); if (boneIndex2JointMap.ContainsKey(boneIndex)) { KinectInterop.JointType joint = flip ? boneIndex2JointMap[boneIndex] : boneIndex2MirrorJointMap[boneIndex]; if (externalHeadRotation && joint == KinectInterop.JointType.Head) // skip head if moved externally { continue; } if (externalHandRotations && // skip hands if moved externally (joint == KinectInterop.JointType.WristLeft || joint == KinectInterop.JointType.WristRight || joint == KinectInterop.JointType.HandLeft || joint == KinectInterop.JointType.HandRight)) { continue; } TransformBone(UserID, joint, boneIndex, flip); } else if (boneIndex >= 21 && boneIndex <= 24) { // fingers or thumbs if (fingerOrientations && !externalHandRotations) { KinectInterop.JointType joint = flip ? boneIndex2FingerMap[boneIndex] : boneIndex2MirrorFingerMap[boneIndex]; TransformSpecialBoneFingers(UserID, (int)joint, boneIndex, flip); } } } } // save pelvis rotation SavePelvisRotation(UserID); // user pose has been applied poseApplied = true; if (applyMuscleLimits && kinectManager && kinectManager.IsUserTracked(UserID)) { // check for limits CheckMuscleLimits(); } // update time lastUpdateTime = Time.time; } /// /// Resets bones to their initial positions and rotations. This also releases avatar control from KM, by settings playerId to 0 /// public virtual void ResetToInitialPosition() { //Debug.Log("ResetToInitialPosition. UserId: " + playerId); 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(); foreach (HumanBodyBones bone in fingerBoneLocalRotations.Keys) { Transform boneTransform = animatorComponent ? animatorComponent.GetBoneTransform(bone) : null; if (boneTransform) { boneTransform.localRotation = fingerBoneLocalRotations[bone]; } } //// Restore the offset's position and rotation //if (offsetNode != null) //{ // offsetNode.transform.position = offsetNodePos; // offsetNode.transform.rotation = offsetNodeRot; //} transform.position = initialPosition; transform.rotation = initialRotation; initialUpVector = transform.up; } /// /// Invoked on the successful calibration of the player. /// /// User identifier. public virtual void SuccessfulCalibration(ulong userId, bool resetInitialTransform) { playerId = userId; //Debug.Log("SuccessfulCalibration. UserId: " + playerId); //// 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; initialUpVector = transform.up; // re-calibrate the position offset offsetCalibrated = false; poseApplied = false; } /// /// Moves the avatar to its initial/base position /// /// world position /// rotation offset public virtual void ResetInitialTransform(Vector3 position, Vector3 rotation) { bodyRootPosition = position; initialPosition = position; initialRotation = Quaternion.Euler(rotation); transform.position = initialPosition; transform.rotation = initialRotation; initialUpVector = transform.up; offsetCalibrated = false; // this causes calibrating offset in MoveAvatar function poseApplied = false; } /// /// Sets the avatar's offset position (position of initial user detection). /// /// New offset position. If zero, sets the current player position as offset position. public void SetOffsetPos(Vector3 pos) { if(pos == Vector3.zero) { pos = kinectManager.GetUserPosition(playerId); } if(pos != Vector3.zero) { offsetPos.x = pos.x; offsetPos.y = pos.y; offsetPos.z = !mirroredMovement && !posRelativeToCamera ? -pos.z : pos.z; offsetCalibrated = true; //Debug.LogWarning($"{gameObject.name} offset set to: {offsetPos:F2}"); } } // Checks if the given joint is part of the legs protected bool IsLegJoint(KinectInterop.JointType joint) { return ((joint == KinectInterop.JointType.HipLeft) || (joint == KinectInterop.JointType.HipRight) || (joint == KinectInterop.JointType.KneeLeft) || (joint == KinectInterop.JointType.KneeRight) || (joint == KinectInterop.JointType.AnkleLeft) || (joint == KinectInterop.JointType.AnkleRight)); } // saves current pelvis rotation protected void SavePelvisRotation(ulong userId) { if (kinectManager != null && kinectManager.IsJointTracked(userId, (int)KinectInterop.JointType.Pelvis)) { Quaternion curPelvisRot = kinectManager.GetJointOrientation(userId, (int)KinectInterop.JointType.Pelvis, false); if (poseApplied) pelvisRotation = Quaternion.RotateTowards(pelvisRotation, curPelvisRot, 90f * Time.deltaTime); // 90 deg/s else pelvisRotation = curPelvisRot; //Debug.Log($" P{playerIndex}, id: {playerId} - Pel: {pelvisRotation.eulerAngles}, Cur: {curPelvisRot.eulerAngles} P: {poseApplied}, dT: {Time.deltaTime:F3}, P: {poseApplied}, dT: {Time.deltaTime:F3}"); } } // returns the angle between the last and current pelvis orientations (in degrees 0-180), or -1 if anything goes wrong protected float GetPelvisAngle(ulong userId, bool flip) { int iJoint = (int)KinectInterop.JointType.Pelvis; if (kinectManager == null || !kinectManager.IsJointTracked(userId, iJoint)) return -1f; // get Kinect joint orientation Quaternion jointRotation = kinectManager.GetJointOrientation(userId, iJoint, flip); if (jointRotation == Quaternion.identity) return -1f; float angle = Quaternion.Angle(pelvisRotation, jointRotation); return angle; } // Apply the rotations tracked by kinect to the joints. protected virtual void TransformBone(ulong 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.GetJointTrackingState(userId, iJoint) < KinectInterop.TrackingState.Tracked)) return; // Get Kinect joint orientation Quaternion jointRotation = kinectManager.GetJointOrientation(userId, iJoint, flip); if (jointRotation == Quaternion.identity && !IsLegJoint(joint)) return; //if (joint == KinectInterop.JointType.WristLeft) //{ // //jointRotation = Quaternion.identity; // Debug.Log(string.Format("AC {0:F3} {1}, user: {2}, state: {3}\npos: {4}, rot: {5}", Time.time, joint, // userId, kinectManager.GetJointTrackingState(userId, iJoint), // kinectManager.GetJointPosition(userId, iJoint), jointRotation.eulerAngles)); //} // calculate the new orientation Quaternion newRotation = Kinect2AvatarRot(jointRotation, boneIndex); if (externalRootMotion) { newRotation = transform.rotation * newRotation; } // Smoothly transition to the new rotation bool isSmoothAllowed = (Time.time - lastUpdateTime) <= MaxUpdateTime; if (isSmoothAllowed && smoothFactor != 0f) boneTransform.rotation = Quaternion.Slerp(boneTransform.rotation, newRotation, smoothFactor * (useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime)); else boneTransform.rotation = newRotation; //if(boneIndex == 5 || boneIndex == 6) // clavicles //{ // Debug.Log(boneIndex + " rot - joint: " + jointRotation.eulerAngles + ", k2a: " + newRotation.eulerAngles + ", trans: " + boneTransform.rotation.eulerAngles); //} } // Apply the rotations tracked by kinect to fingers (one joint = multiple bones) protected virtual void TransformSpecialBoneFingers(ulong 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 && !kinectManager.IsUserTurnedAround(userId)) // { // float angleSign = !mirroredMovement /**(boneIndex == 21 || boneIndex == 22)*/ ? -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 && !kinectManager.IsUserTurnedAround(userId)) // { // float angleSign = !mirroredMovement /**(boneIndex == 21 || boneIndex == 22)*/ ? -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); // } //} bool isJointTracked = kinectManager.IsJointTracked(userId, joint); if (!animatorComponent || !isJointTracked) return; // Get Kinect joint orientation 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 alBones = boneIndex2MultiBoneMap[boneIndex]; // Smoothly transition to the new rotation bool isSmoothAllowed = (Time.time - lastUpdateTime) <= MaxUpdateTime; for (int i = 0; i < alBones.Count; i++) { Transform boneTransform = animatorComponent.GetBoneTransform(alBones[i]); if (!boneTransform) continue; if (isSmoothAllowed && smoothFactor != 0f) boneTransform.rotation = Quaternion.Slerp(boneTransform.rotation, newRotation, smoothFactor * (useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime)); else boneTransform.rotation = newRotation; } } // Apply the rotations needed to transform fingers to fist protected virtual void TransformSpecialBoneFist(int boneIndex, float angle) { if (!animatorComponent) return; List alBones = boneIndex2MultiBoneMap[boneIndex]; for (int i = 0; i < alBones.Count; i++) { if (i < 1 && (boneIndex == 22 || boneIndex == 24)) // skip the first thumb bone 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 virtual void TransformSpecialBoneUnfist(int boneIndex) { if (!animatorComponent) return; List alBones = boneIndex2MultiBoneMap[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 virtual void MoveAvatar(ulong UserID) { if ((moveRate == 0f) || !kinectManager || (kinectManager.GetJointTrackingState(UserID, (int)KinectInterop.JointType.Pelvis) < KinectInterop.TrackingState.Tracked)) { return; } // get the position of user's spine base Vector3 trans = kinectManager.GetUserPosition(UserID); // move avatar transform DoMoveAvatar(UserID, trans); } // Moves the avatar transform protected void DoMoveAvatar(ulong UserID, Vector3 trans) { //Debug.Log("User " + playerIndex + " pos: " + trans); if (flipLeftRight) trans.x = -trans.x; if (posRelativeToCamera) { if (posRelOverlayColor) { // disable grounded feet if(groundedFeet) { groundedFeet = false; } // use the color overlay position int sensorIndex = kinectManager.GetPrimaryBodySensorIndex(); //if (backgroundPlane && planeRectSet) //{ // // get the plane overlay position // trans = kinectManager.GetJointPosColorOverlay(UserID, (int)KinectInterop.JointType.Pelvis, sensorIndex, planeRect); // trans.z = backgroundPlane.position.z - posRelativeToCamera.transform.position.z - 0.1f; // 10cm offset //} //else { Rect backgroundRect = posRelativeToCamera.pixelRect; PortraitBackground portraitBack = PortraitBackground.Instance; if (portraitBack && portraitBack.enabled) { backgroundRect = portraitBack.GetBackgroundRect(); } trans = kinectManager.GetJointPosColorOverlay(UserID, (int)KinectInterop.JointType.Pelvis, sensorIndex, posRelativeToCamera, backgroundRect); } } else { // move according to the camera Vector3 bodyRootPos = bodyRoot != null ? bodyRoot.position : transform.position; Vector3 userLocalPos = kinectManager.GetUserKinectPosition(UserID, true); trans = posRelativeToCamera.transform.TransformPoint(userLocalPos); //Debug.Log(" trans: " + trans + ", localPos: " + userLocalPos + ", camPos: " + posRelativeToCamera.transform.position); if (!horizontalMovement) { trans = new Vector3(bodyRootPos.x, trans.y, bodyRootPos.z); } if (verticalMovement) { trans.y -= hipCenterDist; } else { trans.y = bodyRootPos.y; } //Debug.Log("cameraPos: " + posRelativeToCamera.transform.position + ", cameraRot: " + posRelativeToCamera.transform.rotation.eulerAngles + // ", bodyRoot: " + bodyRootPos + ", hipCenterDist: " + hipCenterDist + ", localPos: " + userLocalPos + ", trans: " + trans); } if (flipLeftRight) trans.x = -trans.x; if(posRelOverlayColor || !offsetCalibrated) { if (bodyRoot != null) { bodyRoot.position = trans; } else { transform.position = trans; } bodyRootPosition = trans; //Debug.Log($"BodyRootPos set: {trans:F2}"); // reset the body offset offsetCalibrated = false; } } // invert the z-coordinate, if needed if (posRelativeToCamera && posRelInvertedZ) { trans.z = -trans.z; } //if (posRelativeToCamera /**&& horizontalMovement*/) //{ // //if(offsetCamPos != posRelativeToCamera.transform.position || offsetCamRot != posRelativeToCamera.transform.rotation) // { // //offsetCamPos = posRelativeToCamera.transform.position; // //offsetCamRot = posRelativeToCamera.transform.rotation; // //Debug.Log("Changed cam pos: " + offsetCamPos + ", rot: " + offsetCamRot.eulerAngles); // } //} if (!offsetCalibrated) { 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; offsetCalibrated = posRelativeToCamera || GetUserHipAngle(UserID) >= 170f; //Debug.LogWarning($"{gameObject.name} offset: {offsetPos:F2}, calibrated: {offsetCalibrated}, hipAngle: {GetUserHipAngle(UserID):F1}"); } // transition to the new position Vector3 targetPos = bodyRootPosition + Kinect2AvatarPos(trans, verticalMovement, horizontalMovement); //Debug.Log(" targetPos: " + targetPos + ", trans: " + trans + ", offsetPos: " + offsetPos + ", bodyRootPos: " + bodyRootPosition); if (isRigidBody && !verticalMovement) { // workaround for obeying the physics (e.g. gravity falling) targetPos.y = bodyRoot != null ? bodyRoot.position.y : transform.position.y; } // fixed bone indices - thanks to Martin Cvengros! var biShoulderL = GetBoneIndexByJoint(KinectInterop.JointType.ShoulderLeft, false); // you may replace 'false' with 'mirroredMovement' var biShoulderR = GetBoneIndexByJoint(KinectInterop.JointType.ShoulderRight, false); // you may replace 'false' with 'mirroredMovement' var biPelvis = GetBoneIndexByJoint(KinectInterop.JointType.Pelvis, false); // you may replace 'false' with 'mirroredMovement' var biNeck = GetBoneIndexByJoint(KinectInterop.JointType.Neck, false); // you may replace 'false' with 'mirroredMovement' // added by r618 if (horizontalMovement && horizontalOffset != 0f && bones[biShoulderL] != null && bones[biShoulderR] != null) { // { 5, HumanBodyBones.LeftUpperArm}, // { 11, HumanBodyBones.RightUpperArm}, //Vector3 dirSpine = bones[5].position - bones[11].position; Vector3 dirShoulders = bones[biShoulderR].position - bones[biShoulderL].position; targetPos += dirShoulders.normalized * horizontalOffset; } if (verticalMovement && verticalOffset != 0f && bones[biPelvis] != null && bones[biNeck] != null) { Vector3 dirSpine = bones[biNeck].position - bones[biPelvis].position; targetPos += dirSpine.normalized * verticalOffset; } if (horizontalMovement && forwardOffset != 0f && bones[biPelvis] != null && bones[biNeck] != null && bones[biShoulderL] != null && bones[biShoulderR] != null) { Vector3 dirSpine = (bones[biNeck].position - bones[biPelvis].position).normalized; Vector3 dirShoulders = (bones[biShoulderR].position - bones[biShoulderL].position).normalized; Vector3 dirForward = Vector3.Cross(dirShoulders, dirSpine).normalized; targetPos += dirForward * forwardOffset; } if (groundedFeet && verticalMovement) // without vertical movement, grounding produces an ever expanding jump up & down { float fNewDistance = GetCorrDistanceToGround(); float fNewDistanceTime = useUnscaledTime ? Time.unscaledTime : Time.time; //Vector3 lastTargetPos = targetPos; if (Mathf.Abs(fNewDistance) >= MaxFootDistanceGround && Mathf.Abs(fFootDistance + fNewDistance) < 1f) // limit the correction to 1 meter { if ((fNewDistanceTime - fFootDistanceTime) >= MaxFootDistanceTime) { fFootDistance += fNewDistance; fFootDistanceTime = fNewDistanceTime; vFootCorrection = initialUpVector * fFootDistance; //Debug.Log($"****{leftFoot.name} pos: {leftFoot.position}, ini: {leftFootPos}, dif: {leftFoot.position - leftFootPos}\n" + // $"****{rightFoot.name} pos: {rightFoot.position}, ini: {rightFootPos}, dif: {rightFoot.position - rightFootPos}\n" + // $"****footDist: {fNewDistance:F2}, footCorr: {vFootCorrection}, {transform.name} pos: {transform.position}"); } } else { fFootDistanceTime = fNewDistanceTime; } targetPos += vFootCorrection; //Debug.Log($"Gnd targetPos: {targetPos}, lastPos: {lastTargetPos}, vFootCorrection: {vFootCorrection}\nfFootDistance: {fFootDistance:F2}, fNewDistance: {fNewDistance:F2}, upVector: {initialUpVector}, distTime: {(fNewDistanceTime - fFootDistanceTime):F3}"); } bool isSmoothAllowed = (Time.time - lastUpdateTime) <= MaxUpdateTime; if (bodyRoot != null) { bodyRoot.position = isSmoothAllowed && smoothFactor != 0f ? Vector3.Lerp(bodyRoot.position, targetPos, smoothFactor * (useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime)) : targetPos; } else { transform.position = isSmoothAllowed && smoothFactor != 0f ? Vector3.Lerp(transform.position, targetPos, smoothFactor * (useUnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime)) : targetPos; } } // Returns the angle at user's hip (knee-hip-neck) protected float GetUserHipAngle(ulong userId) { float angle = 0f; if(kinectManager != null && kinectManager.GetJointTrackingState(userId, (int)KinectInterop.JointType.Pelvis) >= KinectInterop.TrackingState.Tracked && kinectManager.GetJointTrackingState(userId, (int)KinectInterop.JointType.Neck) >= KinectInterop.TrackingState.Tracked && kinectManager.GetJointTrackingState(userId, (int)KinectInterop.JointType.KneeLeft) >= KinectInterop.TrackingState.Tracked && kinectManager.GetJointTrackingState(userId, (int)KinectInterop.JointType.KneeRight) >= KinectInterop.TrackingState.Tracked) { Vector3 posPelvis = kinectManager.GetJointPosition(userId, (int)KinectInterop.JointType.Pelvis); Vector3 posNeck = kinectManager.GetJointPosition(userId, (int)KinectInterop.JointType.Neck); Vector3 posKneeL = kinectManager.GetJointPosition(userId, (int)KinectInterop.JointType.KneeLeft); Vector3 posKneeR = kinectManager.GetJointPosition(userId, (int)KinectInterop.JointType.KneeRight); Vector3 posKneeC = (posKneeL + posKneeR) / 2f; angle = Vector3.Angle(posNeck - posPelvis, posKneeC - posPelvis); } return angle; } // Set model's arms to be in T-pose protected virtual 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() { for (int boneIndex = 0; boneIndex < bones.Length; boneIndex++) { if (!boneIndex2MecanimMap.ContainsKey(boneIndex)) continue; bones[boneIndex] = animatorComponent ? animatorComponent.GetBoneTransform(boneIndex2MecanimMap[boneIndex]) : null; } //// map finger bones, too //fingerBones = new Transform[fingerIndex2MecanimMap.Count]; //for (int boneIndex = 0; boneIndex < fingerBones.Length; boneIndex++) //{ // if (!fingerIndex2MecanimMap.ContainsKey(boneIndex)) // continue; // fingerBones[boneIndex] = animatorComponent ? animatorComponent.GetBoneTransform(fingerIndex2MecanimMap[boneIndex]) : null; //} } // creates the joint and bone colliders protected virtual void CreateBoneColliders() { if (boneColliderRadius <= 0f) return; boneColliders = new CapsuleCollider[bones.Length]; boneColTrans = new Transform[bones.Length]; boneColJoint = new Transform[bones.Length]; boneColParent = new Transform[bones.Length]; for (int i = 0; i < bones.Length; i++) { if (bones[i] == null) continue; SphereCollider jCollider = bones[i].gameObject.AddComponent(); jCollider.radius = boneColliderRadius; if (i > 0) { GameObject objBoneCollider = new GameObject("BoneCollider" + i); objBoneCollider.transform.parent = bones[i]; boneColTrans[i] = objBoneCollider.transform; CapsuleCollider bCollider = objBoneCollider.AddComponent(); bCollider.radius = boneColliderRadius; bCollider.height = 0f; boneColliders[i] = bCollider; } } for (int i = 0; i < bones.Length; i++) { if (boneColliders[i] == null) continue; boneColJoint[i] = bones[i]; Transform parentTrans = boneColJoint[i].parent; while (parentTrans != null) { if (parentTrans.GetComponent() != null) break; parentTrans = parentTrans.parent; } if (parentTrans != null) boneColParent[i] = parentTrans; else boneColliders[i] = null; } } // updates the bone colliders, as needed protected void UpdateBoneColliders() { if (boneColliders == null) return; for (int i = 0; i < bones.Length; i++) { if (boneColliders[i] == null) continue; Vector3 posJoint = boneColJoint[i].position; Vector3 posParent = boneColParent[i].position; Vector3 dirFromParent = posJoint - posParent; boneColTrans[i].position = posParent + dirFromParent / 2f; boneColTrans[i].up = dirFromParent.normalized; boneColliders[i].height = dirFromParent.magnitude; } } // 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; initialUpVector = transform.up; 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 - offsetNode.position; } // 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 foreach (int boneIndex in boneIndex2MultiBoneMap.Keys) { List alBones = boneIndex2MultiBoneMap[boneIndex]; 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; // 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; } } } } // 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 (!externalRootMotion) // fix by Mathias Parger { newRotation = initialRotation * newRotation; if (offsetNode != null) { newRotation = offsetNode.rotation * 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, bool bMoveHorizontally) { 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(bMoveHorizontally ? xPos : 0f, bMoveVertically ? yPos : 0f, bMoveHorizontally ? zPos : 0f); Quaternion posRotation = mirroredMovement ? Quaternion.Euler(0f, 180f, 0f) * initialRotation : initialRotation; newPosition = posRotation * newPosition; if (offsetNode != null) { //newPosition += offsetNode.transform.position; newPosition = offsetNode.position; } return newPosition; } // returns distance from the given transform to its initial position protected virtual float GetCorrDistanceToGround(Transform trans, Vector3 initialPos, bool isRightJoint) { if (!trans) return 0f; Vector3 deltaDir = trans.position - initialPos; Vector3 vTrans = new Vector3(deltaDir.x * initialUpVector.x, deltaDir.y * initialUpVector.y, deltaDir.z * initialUpVector.z); float fSign = Vector3.Dot(deltaDir, initialUpVector) < 0f ? 1f : -1f; // change the sign, because it's a correction float deltaDist = fSign * vTrans.magnitude; return deltaDist; } // returns the min distance distance from left or right foot to the ground, or 0 if no LF/RF are found protected virtual float GetCorrDistanceToGround() { //if (leftFoot == null && rightFoot == null) //{ // 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)); // } // leftFootPos = leftFoot != null ? leftFoot.position : Vector3.zero; // rightFootPos = rightFoot != null ? rightFoot.position : Vector3.zero; //} float fDistMin = 1000f; float fDistLeft = leftFoot ? GetCorrDistanceToGround(leftFoot, leftFootPos, false) : fDistMin; float fDistRight = rightFoot ? GetCorrDistanceToGround(rightFoot, rightFootPos, true) : fDistMin; fDistMin = Mathf.Abs(fDistLeft) < Mathf.Abs(fDistRight) ? fDistLeft : fDistRight; if (fDistMin == 1000f) { fDistMin = 0f; } return fDistMin; } // protected void OnCollisionEnter(Collision col) // { // Debug.Log("Collision entered"); // } // // protected void OnCollisionExit(Collision col) // { // Debug.Log("Collision exited"); // } // dictionaries to speed up bone processing protected static readonly Dictionary boneIndex2MecanimMap = new Dictionary { {0, HumanBodyBones.Hips}, {1, HumanBodyBones.Spine}, {2, HumanBodyBones.Chest}, {3, HumanBodyBones.Neck}, {4, HumanBodyBones.Head}, {5, HumanBodyBones.LeftShoulder}, {6, HumanBodyBones.LeftUpperArm}, {7, HumanBodyBones.LeftLowerArm}, {8, HumanBodyBones.LeftHand}, {9, HumanBodyBones.RightShoulder}, {10, HumanBodyBones.RightUpperArm}, {11, HumanBodyBones.RightLowerArm}, {12, HumanBodyBones.RightHand}, {13, HumanBodyBones.LeftUpperLeg}, {14, HumanBodyBones.LeftLowerLeg}, {15, HumanBodyBones.LeftFoot}, {16, HumanBodyBones.LeftToes}, {17, HumanBodyBones.RightUpperLeg}, {18, HumanBodyBones.RightLowerLeg}, {19, HumanBodyBones.RightFoot}, {20, HumanBodyBones.RightToes}, {21, HumanBodyBones.LeftIndexProximal}, {22, HumanBodyBones.LeftThumbProximal}, {23, HumanBodyBones.RightIndexProximal}, {24, HumanBodyBones.RightThumbProximal}, }; protected static readonly Dictionary boneIndex2JointMap = new Dictionary { {0, KinectInterop.JointType.Pelvis}, {1, KinectInterop.JointType.SpineNaval}, {2, KinectInterop.JointType.SpineChest}, {3, KinectInterop.JointType.Neck}, {4, KinectInterop.JointType.Head}, {5, KinectInterop.JointType.ClavicleLeft}, {6, KinectInterop.JointType.ShoulderLeft}, {7, KinectInterop.JointType.ElbowLeft}, {8, KinectInterop.JointType.WristLeft}, {9, KinectInterop.JointType.ClavicleRight}, {10, KinectInterop.JointType.ShoulderRight}, {11, KinectInterop.JointType.ElbowRight}, {12, KinectInterop.JointType.WristRight}, {13, KinectInterop.JointType.HipLeft}, {14, KinectInterop.JointType.KneeLeft}, {15, KinectInterop.JointType.AnkleLeft}, {16, KinectInterop.JointType.FootLeft}, {17, KinectInterop.JointType.HipRight}, {18, KinectInterop.JointType.KneeRight}, {19, KinectInterop.JointType.AnkleRight}, {20, KinectInterop.JointType.FootRight}, }; protected static readonly Dictionary boneIndex2MirrorJointMap = new Dictionary { {0, KinectInterop.JointType.Pelvis}, {1, KinectInterop.JointType.SpineNaval}, {2, KinectInterop.JointType.SpineChest}, {3, KinectInterop.JointType.Neck}, {4, KinectInterop.JointType.Head}, {5, KinectInterop.JointType.ClavicleRight}, {6, KinectInterop.JointType.ShoulderRight}, {7, KinectInterop.JointType.ElbowRight}, {8, KinectInterop.JointType.WristRight}, {9, KinectInterop.JointType.ClavicleLeft}, {10, KinectInterop.JointType.ShoulderLeft}, {11, KinectInterop.JointType.ElbowLeft}, {12, KinectInterop.JointType.WristLeft}, {13, KinectInterop.JointType.HipRight}, {14, KinectInterop.JointType.KneeRight}, {15, KinectInterop.JointType.AnkleRight}, {16, KinectInterop.JointType.FootRight}, {17, KinectInterop.JointType.HipLeft}, {18, KinectInterop.JointType.KneeLeft}, {19, KinectInterop.JointType.AnkleLeft}, {20, KinectInterop.JointType.FootLeft}, }; protected static readonly Dictionary jointMap2boneIndex = new Dictionary { {KinectInterop.JointType.Pelvis, 0}, {KinectInterop.JointType.SpineNaval, 1}, {KinectInterop.JointType.SpineChest, 2}, {KinectInterop.JointType.Neck, 3}, {KinectInterop.JointType.Head, 4}, {KinectInterop.JointType.ClavicleLeft, 5}, {KinectInterop.JointType.ShoulderLeft, 6}, {KinectInterop.JointType.ElbowLeft, 7}, {KinectInterop.JointType.WristLeft, 8}, {KinectInterop.JointType.ClavicleRight, 9}, {KinectInterop.JointType.ShoulderRight, 10}, {KinectInterop.JointType.ElbowRight, 11}, {KinectInterop.JointType.WristRight, 12}, {KinectInterop.JointType.HipLeft, 13}, {KinectInterop.JointType.KneeLeft, 14}, {KinectInterop.JointType.AnkleLeft, 15}, {KinectInterop.JointType.FootLeft, 16}, {KinectInterop.JointType.HipRight, 17}, {KinectInterop.JointType.KneeRight, 18}, {KinectInterop.JointType.AnkleRight, 19}, {KinectInterop.JointType.FootRight, 20}, }; protected static readonly Dictionary mirrorJointMap2boneIndex = new Dictionary { {KinectInterop.JointType.Pelvis, 0}, {KinectInterop.JointType.SpineNaval, 1}, {KinectInterop.JointType.SpineChest, 2}, {KinectInterop.JointType.Neck, 3}, {KinectInterop.JointType.Head, 4}, {KinectInterop.JointType.ClavicleRight, 5}, {KinectInterop.JointType.ShoulderRight, 6}, {KinectInterop.JointType.ElbowRight, 7}, {KinectInterop.JointType.WristRight, 8}, {KinectInterop.JointType.ClavicleLeft, 9}, {KinectInterop.JointType.ShoulderLeft, 10}, {KinectInterop.JointType.ElbowLeft, 11}, {KinectInterop.JointType.WristLeft, 12}, {KinectInterop.JointType.HipRight, 13}, {KinectInterop.JointType.KneeRight, 14}, {KinectInterop.JointType.AnkleRight, 15}, {KinectInterop.JointType.FootRight, 16}, {KinectInterop.JointType.HipLeft, 17}, {KinectInterop.JointType.KneeLeft, 18}, {KinectInterop.JointType.AnkleLeft, 19}, {KinectInterop.JointType.FootLeft, 20}, }; protected static readonly Dictionary boneIndex2FingerMap = new Dictionary { {21, KinectInterop.JointType.HandtipLeft}, {22, KinectInterop.JointType.ThumbLeft}, {23, KinectInterop.JointType.HandtipRight}, {24, KinectInterop.JointType.ThumbRight}, }; protected static readonly Dictionary boneIndex2MirrorFingerMap = new Dictionary { {21, KinectInterop.JointType.HandtipRight}, {22, KinectInterop.JointType.ThumbRight}, {23, KinectInterop.JointType.HandtipLeft}, {24, KinectInterop.JointType.ThumbLeft}, }; protected static readonly Dictionary> boneIndex2MultiBoneMap = new Dictionary> { {21, new List { // 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, }}, {22, new List { // left thumb HumanBodyBones.LeftThumbProximal, HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal, }}, {23, new List { // 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, }}, {24, new List { // right thumb HumanBodyBones.RightThumbProximal, HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal, }}, }; } }