dwelling act 4 (live motion cap w/ kinect azure)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1725 lines
72 KiB

using UnityEngine;
//using Windows.Kinect;
using System;
using System.Collections;
using System.Collections.Generic;
using com.rfilkov.kinect;
namespace com.rfilkov.components
{
/// <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 = 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<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 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
/// <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 && bones != null && index < bones.Length)
{
return bones[index];
}
return null;
}
/// <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 list of AC-controlled mecanim bones.
/// </summary>
/// <returns>List of AC-controlled mecanim bones</returns>
public List<HumanBodyBones> GetMecanimBones()
{
List<HumanBodyBones> alMecanimBones = new List<HumanBodyBones>();
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<Transform>() 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<Animator>();
// 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<Rigidbody>() != 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.");
}
}
/// <summary>
/// Updates the avatar each frame.
/// </summary>
/// <param name="UserID">User ID</param>
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;
}
/// <summary>
/// Resets bones to their initial positions and rotations. This also releases avatar control from KM, by settings playerId to 0
/// </summary>
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<Animator>();
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;
}
/// <summary>
/// Invoked on the successful calibration of the player.
/// </summary>
/// <param name="userId">User identifier.</param>
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;
}
/// <summary>
/// Moves the avatar to its initial/base position
/// </summary>
/// <param name="position"> world position </param>
/// <param name="rotation"> rotation offset </param>
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;
}
/// <summary>
/// Sets the avatar's offset position (position of initial user detection).
/// </summary>
/// <param name="pos">New offset position. If zero, sets the current player position as offset position.</param>
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<HumanBodyBones> 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<HumanBodyBones> 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<HumanBodyBones> 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<SphereCollider>();
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<CapsuleCollider>();
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<SphereCollider>() != 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<HumanBodyBones> 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<int, HumanBodyBones> boneIndex2MecanimMap = new Dictionary<int, HumanBodyBones>
{
{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<int, KinectInterop.JointType> boneIndex2JointMap = new Dictionary<int, KinectInterop.JointType>
{
{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<int, KinectInterop.JointType> boneIndex2MirrorJointMap = new Dictionary<int, KinectInterop.JointType>
{
{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<KinectInterop.JointType, int> jointMap2boneIndex = new Dictionary<KinectInterop.JointType, int>
{
{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<KinectInterop.JointType, int> mirrorJointMap2boneIndex = new Dictionary<KinectInterop.JointType, int>
{
{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<int, KinectInterop.JointType> boneIndex2FingerMap = new Dictionary<int, KinectInterop.JointType>
{
{21, KinectInterop.JointType.HandtipLeft},
{22, KinectInterop.JointType.ThumbLeft},
{23, KinectInterop.JointType.HandtipRight},
{24, KinectInterop.JointType.ThumbRight},
};
protected static readonly Dictionary<int, KinectInterop.JointType> boneIndex2MirrorFingerMap = new Dictionary<int, KinectInterop.JointType>
{
{21, KinectInterop.JointType.HandtipRight},
{22, KinectInterop.JointType.ThumbRight},
{23, KinectInterop.JointType.HandtipLeft},
{24, KinectInterop.JointType.ThumbLeft},
};
protected static readonly Dictionary<int, List<HumanBodyBones>> boneIndex2MultiBoneMap = new Dictionary<int, List<HumanBodyBones>>
{
{21, 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,
}},
{22, new List<HumanBodyBones> { // left thumb
HumanBodyBones.LeftThumbProximal,
HumanBodyBones.LeftThumbIntermediate,
HumanBodyBones.LeftThumbDistal,
}},
{23, 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,
}},
{24, new List<HumanBodyBones> { // right thumb
HumanBodyBones.RightThumbProximal,
HumanBodyBones.RightThumbIntermediate,
HumanBodyBones.RightThumbDistal,
}},
};
}
}