You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			643 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			643 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C#
		
	
using UnityEngine;
 | 
						|
using System.Collections;
 | 
						|
 | 
						|
namespace RootMotion
 | 
						|
{
 | 
						|
    public static class BakerUtilities
 | 
						|
    {
 | 
						|
 | 
						|
        public static void ReduceKeyframes(AnimationCurve curve, float maxError)
 | 
						|
        {
 | 
						|
            if (maxError <= 0f) return;
 | 
						|
 | 
						|
            curve.keys = GetReducedKeyframes(curve, maxError);
 | 
						|
 | 
						|
            // TODO Flatten outTangent for keys that have the next key and testAfter sampled to the same value in the original clip. Same thing for the inTangent
 | 
						|
        }
 | 
						|
 | 
						|
        public static Keyframe[] GetReducedKeyframes(AnimationCurve curve, float maxError)
 | 
						|
        {
 | 
						|
            Keyframe[] keys = curve.keys;
 | 
						|
 | 
						|
            int i = 1;
 | 
						|
            while (i < keys.Length - 1 && keys.Length > 2)
 | 
						|
            {
 | 
						|
                Keyframe[] testKeys = new Keyframe[keys.Length - 1];
 | 
						|
                int c = 0;
 | 
						|
                for (int n = 0; n < keys.Length; n++)
 | 
						|
                {
 | 
						|
                    if (i != n)
 | 
						|
                    {
 | 
						|
                        testKeys[c] = new Keyframe(keys[n].time, keys[n].value, keys[n].inTangent, keys[n].outTangent);
 | 
						|
                        c++;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                AnimationCurve testCurve = new AnimationCurve();
 | 
						|
                testCurve.keys = testKeys;
 | 
						|
 | 
						|
                float test0 = Mathf.Abs(testCurve.Evaluate(keys[i].time) - keys[i].value);
 | 
						|
                float beforeTime = keys[i].time + (keys[i - 1].time - keys[i].time) * 0.5f;
 | 
						|
                float afterTime = keys[i].time + (keys[i + 1].time - keys[i].time) * 0.5f;
 | 
						|
 | 
						|
                float testBefore = Mathf.Abs(testCurve.Evaluate(beforeTime) - curve.Evaluate(beforeTime));
 | 
						|
                float testAfter = Mathf.Abs(testCurve.Evaluate(afterTime) - curve.Evaluate(afterTime));
 | 
						|
 | 
						|
                if (test0 < maxError && testBefore < maxError && testAfter < maxError)
 | 
						|
                {
 | 
						|
                    keys = testKeys;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    i++;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return keys;
 | 
						|
        }
 | 
						|
 | 
						|
        public static void SetLoopFrame(float time, AnimationCurve curve)
 | 
						|
        {
 | 
						|
            /*
 | 
						|
            Keyframe[] keys = curve.keys;
 | 
						|
            keys[keys.Length - 1].value = keys[0].value;
 | 
						|
 | 
						|
            keys[keys.Length - 1].inTangent = keys[0].inTangent;
 | 
						|
            keys[keys.Length - 1].outTangent = keys[0].outTangent;
 | 
						|
 | 
						|
            keys[keys.Length - 1].time = time;
 | 
						|
            curve.keys = keys;
 | 
						|
            */
 | 
						|
 | 
						|
            Keyframe[] keys = curve.keys;
 | 
						|
            keys[keys.Length - 1].value = keys[0].value;
 | 
						|
 | 
						|
            float inTangent = Mathf.Lerp(keys[0].inTangent, keys[keys.Length - 1].inTangent, 0.5f);
 | 
						|
            keys[0].inTangent = inTangent;
 | 
						|
            keys[keys.Length - 1].inTangent = inTangent;
 | 
						|
 | 
						|
            float outTangent = Mathf.Lerp(keys[0].outTangent, keys[keys.Length - 1].outTangent, 0.5f);
 | 
						|
            keys[0].outTangent = outTangent;
 | 
						|
            keys[keys.Length - 1].outTangent = outTangent;
 | 
						|
 | 
						|
            keys[keys.Length - 1].time = time;
 | 
						|
            curve.keys = keys;
 | 
						|
        }
 | 
						|
 | 
						|
        public static void SetTangentMode(AnimationCurve curve)
 | 
						|
        {
 | 
						|
#if UNITY_EDITOR
 | 
						|
 | 
						|
            if (curve.length < 2) return;
 | 
						|
 | 
						|
            for (int i = 1; i < curve.length - 1; i++)
 | 
						|
            {
 | 
						|
                UnityEditor.AnimationUtility.SetKeyLeftTangentMode(curve, i, UnityEditor.AnimationUtility.TangentMode.ClampedAuto);
 | 
						|
                UnityEditor.AnimationUtility.SetKeyRightTangentMode(curve, i, UnityEditor.AnimationUtility.TangentMode.ClampedAuto);
 | 
						|
            }
 | 
						|
 | 
						|
#endif
 | 
						|
        }
 | 
						|
 | 
						|
        // Realigns quaternion keys to ensure shortest interpolation paths.
 | 
						|
        public static Quaternion EnsureQuaternionContinuity(Quaternion lastQ, Quaternion q)
 | 
						|
        {
 | 
						|
            Quaternion flipped = new Quaternion(-q.x, -q.y, -q.z, -q.w);
 | 
						|
 | 
						|
            Quaternion midQ = new Quaternion(
 | 
						|
                Mathf.Lerp(lastQ.x, q.x, 0.5f),
 | 
						|
                Mathf.Lerp(lastQ.y, q.y, 0.5f),
 | 
						|
                Mathf.Lerp(lastQ.z, q.z, 0.5f),
 | 
						|
                Mathf.Lerp(lastQ.w, q.w, 0.5f)
 | 
						|
                );
 | 
						|
 | 
						|
            Quaternion midQFlipped = new Quaternion(
 | 
						|
                Mathf.Lerp(lastQ.x, flipped.x, 0.5f),
 | 
						|
                Mathf.Lerp(lastQ.y, flipped.y, 0.5f),
 | 
						|
                Mathf.Lerp(lastQ.z, flipped.z, 0.5f),
 | 
						|
                Mathf.Lerp(lastQ.w, flipped.w, 0.5f)
 | 
						|
                );
 | 
						|
 | 
						|
            float angle = Quaternion.Angle(lastQ, midQ);
 | 
						|
            float angleFlipped = Quaternion.Angle(lastQ, midQFlipped);
 | 
						|
 | 
						|
            return angleFlipped < angle ? flipped : q;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    //Manages the Animation Curves for Humanoid Q/T channels.
 | 
						|
    [System.Serializable]
 | 
						|
    public class BakerHumanoidQT
 | 
						|
    {
 | 
						|
 | 
						|
        private Transform transform;
 | 
						|
        private string Qx, Qy, Qz, Qw;
 | 
						|
        private string Tx, Ty, Tz;
 | 
						|
 | 
						|
        // Animation curves for each channel of the Transform
 | 
						|
        public AnimationCurve rotX, rotY, rotZ, rotW;
 | 
						|
        public AnimationCurve posX, posY, posZ;
 | 
						|
 | 
						|
        private AvatarIKGoal goal;
 | 
						|
        private Quaternion lastQ;
 | 
						|
        private bool lastQSet;
 | 
						|
 | 
						|
        // The custom constructor
 | 
						|
        public BakerHumanoidQT(string name)
 | 
						|
        {
 | 
						|
            Qx = name + "Q.x";
 | 
						|
            Qy = name + "Q.y";
 | 
						|
            Qz = name + "Q.z";
 | 
						|
            Qw = name + "Q.w";
 | 
						|
 | 
						|
            Tx = name + "T.x";
 | 
						|
            Ty = name + "T.y";
 | 
						|
            Tz = name + "T.z";
 | 
						|
 | 
						|
            Reset();
 | 
						|
        }
 | 
						|
 | 
						|
        public BakerHumanoidQT(Transform transform, AvatarIKGoal goal, string name)
 | 
						|
        {
 | 
						|
            this.transform = transform;
 | 
						|
            this.goal = goal;
 | 
						|
 | 
						|
            Qx = name + "Q.x";
 | 
						|
            Qy = name + "Q.y";
 | 
						|
            Qz = name + "Q.z";
 | 
						|
            Qw = name + "Q.w";
 | 
						|
 | 
						|
            Tx = name + "T.x";
 | 
						|
            Ty = name + "T.y";
 | 
						|
            Tz = name + "T.z";
 | 
						|
 | 
						|
            Reset();
 | 
						|
        }
 | 
						|
 | 
						|
        public Quaternion EvaluateRotation(float time)
 | 
						|
        {
 | 
						|
            Quaternion q = new Quaternion(rotX.Evaluate(time), rotY.Evaluate(time), rotZ.Evaluate(time), rotW.Evaluate(time));
 | 
						|
            return q;
 | 
						|
            //return q.normalized;
 | 
						|
        }
 | 
						|
 | 
						|
        public Vector3 EvaluatePosition(float time)
 | 
						|
        {
 | 
						|
            return new Vector3(posX.Evaluate(time), posY.Evaluate(time), posZ.Evaluate(time));
 | 
						|
        }
 | 
						|
 | 
						|
        public TQ Evaluate(float time)
 | 
						|
        {
 | 
						|
            return new TQ(EvaluatePosition(time), EvaluateRotation(time));
 | 
						|
        }
 | 
						|
 | 
						|
        public void GetCurvesFromClip(AnimationClip clip, Animator animator)
 | 
						|
        {
 | 
						|
#if UNITY_EDITOR
 | 
						|
            rotX = GetEditorCurve(clip, Qx);
 | 
						|
            rotY = GetEditorCurve(clip, Qy);
 | 
						|
            rotZ = GetEditorCurve(clip, Qz);
 | 
						|
            rotW = GetEditorCurve(clip, Qw);
 | 
						|
 | 
						|
            posX = GetEditorCurve(clip, Tx);
 | 
						|
            posY = GetEditorCurve(clip, Ty);
 | 
						|
            posZ = GetEditorCurve(clip, Tz);
 | 
						|
#endif
 | 
						|
        }
 | 
						|
 | 
						|
#if UNITY_EDITOR
 | 
						|
        private AnimationCurve GetEditorCurve(AnimationClip clip, string propertyPath)
 | 
						|
        {
 | 
						|
            var binding = UnityEditor.EditorCurveBinding.FloatCurve(string.Empty, typeof(Animator), propertyPath);
 | 
						|
            return UnityEditor.AnimationUtility.GetEditorCurve(clip, binding);
 | 
						|
        }
 | 
						|
#endif
 | 
						|
 | 
						|
        // Clear all curves
 | 
						|
        public void Reset()
 | 
						|
        {
 | 
						|
            rotX = new AnimationCurve();
 | 
						|
            rotY = new AnimationCurve();
 | 
						|
            rotZ = new AnimationCurve();
 | 
						|
            rotW = new AnimationCurve();
 | 
						|
 | 
						|
            posX = new AnimationCurve();
 | 
						|
            posY = new AnimationCurve();
 | 
						|
            posZ = new AnimationCurve();
 | 
						|
 | 
						|
            lastQ = Quaternion.identity;
 | 
						|
            lastQSet = false;
 | 
						|
        }
 | 
						|
 | 
						|
        public void SetIKKeyframes(float time, Avatar avatar, Transform root, float humanScale, Vector3 bodyPosition, Quaternion bodyRotation)
 | 
						|
        {
 | 
						|
            Vector3 bonePos = transform.position;
 | 
						|
            Quaternion boneRot = transform.rotation;
 | 
						|
 | 
						|
            if (root.parent != null)
 | 
						|
            {
 | 
						|
                bonePos = root.parent.InverseTransformPoint(bonePos);
 | 
						|
                boneRot = Quaternion.Inverse(root.parent.rotation) * boneRot;
 | 
						|
            }
 | 
						|
 | 
						|
            TQ IKTQ = AvatarUtility.GetIKGoalTQ(avatar, humanScale, goal, new TQ(bodyPosition, bodyRotation), new TQ(bonePos, boneRot));
 | 
						|
 | 
						|
            Quaternion rot = IKTQ.q;
 | 
						|
            if (lastQSet) rot = BakerUtilities.EnsureQuaternionContinuity(lastQ, IKTQ.q);
 | 
						|
 | 
						|
            //rot.Normalize();
 | 
						|
 | 
						|
            lastQ = rot;
 | 
						|
            lastQSet = true;
 | 
						|
 | 
						|
            rotX.AddKey(time, rot.x);
 | 
						|
            rotY.AddKey(time, rot.y);
 | 
						|
            rotZ.AddKey(time, rot.z);
 | 
						|
            rotW.AddKey(time, rot.w);
 | 
						|
 | 
						|
            Vector3 pos = IKTQ.t;
 | 
						|
            posX.AddKey(time, pos.x);
 | 
						|
            posY.AddKey(time, pos.y);
 | 
						|
            posZ.AddKey(time, pos.z);
 | 
						|
        }
 | 
						|
 | 
						|
        public void SetKeyframes(float time, Vector3 pos, Quaternion rot)
 | 
						|
        {
 | 
						|
            // Rotation flipping already prevented in HumanoidBaker.UpdateHumanPose().
 | 
						|
            rotX.AddKey(time, rot.x);
 | 
						|
            rotY.AddKey(time, rot.y);
 | 
						|
            rotZ.AddKey(time, rot.z);
 | 
						|
            rotW.AddKey(time, rot.w);
 | 
						|
 | 
						|
            posX.AddKey(time, pos.x);
 | 
						|
            posY.AddKey(time, pos.y);
 | 
						|
            posZ.AddKey(time, pos.z);
 | 
						|
        }
 | 
						|
 | 
						|
        public void MoveLastKeyframes(float time)
 | 
						|
        {
 | 
						|
            MoveLastKeyframe(time, rotX);
 | 
						|
            MoveLastKeyframe(time, rotY);
 | 
						|
            MoveLastKeyframe(time, rotZ);
 | 
						|
            MoveLastKeyframe(time, rotW);
 | 
						|
 | 
						|
            MoveLastKeyframe(time, posX);
 | 
						|
            MoveLastKeyframe(time, posY);
 | 
						|
            MoveLastKeyframe(time, posZ);
 | 
						|
        }
 | 
						|
 | 
						|
        // Add a copy of the first frame to the specified time
 | 
						|
        public void SetLoopFrame(float time)
 | 
						|
        {
 | 
						|
            BakerUtilities.SetLoopFrame(time, rotX);
 | 
						|
            BakerUtilities.SetLoopFrame(time, rotY);
 | 
						|
            BakerUtilities.SetLoopFrame(time, rotZ);
 | 
						|
            BakerUtilities.SetLoopFrame(time, rotW);
 | 
						|
 | 
						|
            BakerUtilities.SetLoopFrame(time, posX);
 | 
						|
            BakerUtilities.SetLoopFrame(time, posY);
 | 
						|
            BakerUtilities.SetLoopFrame(time, posZ);
 | 
						|
        }
 | 
						|
 | 
						|
        public void SetRootLoopFrame(float time)
 | 
						|
        {
 | 
						|
            /*
 | 
						|
            // TODO Should be based on AnimationClipSettings
 | 
						|
            BakerUtilities.SetLoopFrame(time, rotX);
 | 
						|
            BakerUtilities.SetLoopFrame(time, rotY);
 | 
						|
            BakerUtilities.SetLoopFrame(time, rotZ);
 | 
						|
            BakerUtilities.SetLoopFrame(time, rotW);
 | 
						|
            
 | 
						|
            BakerUtilities.SetLoopFrame(time, posY);
 | 
						|
            */
 | 
						|
        }
 | 
						|
 | 
						|
        private void MoveLastKeyframe(float time, AnimationCurve curve)
 | 
						|
        {
 | 
						|
            Keyframe[] keys = curve.keys;
 | 
						|
            keys[keys.Length - 1].time = time;
 | 
						|
            curve.keys = keys;
 | 
						|
        }
 | 
						|
 | 
						|
        public void MultiplyLength(AnimationCurve curve, float mlp)
 | 
						|
        {
 | 
						|
            Keyframe[] keys = curve.keys;
 | 
						|
            for (int i = 0; i < keys.Length; i++)
 | 
						|
            {
 | 
						|
                keys[i].time *= mlp;
 | 
						|
            }
 | 
						|
            curve.keys = keys;
 | 
						|
        }
 | 
						|
 | 
						|
        // Add curves to the AnimationClip for each channel
 | 
						|
        public void SetCurves(ref AnimationClip clip, float maxError, float lengthMlp)
 | 
						|
        {
 | 
						|
            MultiplyLength(rotX, lengthMlp);
 | 
						|
            MultiplyLength(rotY, lengthMlp);
 | 
						|
            MultiplyLength(rotZ, lengthMlp);
 | 
						|
            MultiplyLength(rotW, lengthMlp);
 | 
						|
 | 
						|
            MultiplyLength(posX, lengthMlp);
 | 
						|
            MultiplyLength(posY, lengthMlp);
 | 
						|
            MultiplyLength(posZ, lengthMlp);
 | 
						|
 | 
						|
            BakerUtilities.ReduceKeyframes(rotX, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(rotY, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(rotZ, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(rotW, maxError);
 | 
						|
 | 
						|
            BakerUtilities.ReduceKeyframes(posX, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(posY, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(posZ, maxError);
 | 
						|
 | 
						|
            BakerUtilities.SetTangentMode(rotX);
 | 
						|
            BakerUtilities.SetTangentMode(rotY);
 | 
						|
            BakerUtilities.SetTangentMode(rotZ);
 | 
						|
            BakerUtilities.SetTangentMode(rotW);
 | 
						|
 | 
						|
            /*
 | 
						|
            BakerUtilities.SetTangentMode(posX);
 | 
						|
            BakerUtilities.SetTangentMode(posY);
 | 
						|
            BakerUtilities.SetTangentMode(posZ);
 | 
						|
            */
 | 
						|
 | 
						|
            clip.SetCurve(string.Empty, typeof(Animator), Qx, rotX);
 | 
						|
            clip.SetCurve(string.Empty, typeof(Animator), Qy, rotY);
 | 
						|
            clip.SetCurve(string.Empty, typeof(Animator), Qz, rotZ);
 | 
						|
            clip.SetCurve(string.Empty, typeof(Animator), Qw, rotW);
 | 
						|
 | 
						|
            clip.SetCurve(string.Empty, typeof(Animator), Tx, posX);
 | 
						|
            clip.SetCurve(string.Empty, typeof(Animator), Ty, posY);
 | 
						|
            clip.SetCurve(string.Empty, typeof(Animator), Tz, posZ);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Manages the Animation Curves for a single Transform that is a child of the root Transform.
 | 
						|
    [System.Serializable]
 | 
						|
    public class BakerMuscle
 | 
						|
    {
 | 
						|
 | 
						|
        // Animation curves for each channel of the Transform
 | 
						|
        public AnimationCurve curve;
 | 
						|
 | 
						|
        private int muscleIndex = -1;
 | 
						|
        private string propertyName;
 | 
						|
 | 
						|
        // The custom constructor
 | 
						|
        public BakerMuscle(int muscleIndex)
 | 
						|
        {
 | 
						|
            this.muscleIndex = muscleIndex;
 | 
						|
            this.propertyName = MuscleNameToPropertyName(HumanTrait.MuscleName[muscleIndex]);
 | 
						|
 | 
						|
            Reset();
 | 
						|
        }
 | 
						|
 | 
						|
        private string MuscleNameToPropertyName(string n)
 | 
						|
        {
 | 
						|
            // Left fingers
 | 
						|
            if (n == "Left Index 1 Stretched") return "LeftHand.Index.1 Stretched";
 | 
						|
            if (n == "Left Index 2 Stretched") return "LeftHand.Index.2 Stretched";
 | 
						|
            if (n == "Left Index 3 Stretched") return "LeftHand.Index.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Left Middle 1 Stretched") return "LeftHand.Middle.1 Stretched";
 | 
						|
            if (n == "Left Middle 2 Stretched") return "LeftHand.Middle.2 Stretched";
 | 
						|
            if (n == "Left Middle 3 Stretched") return "LeftHand.Middle.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Left Ring 1 Stretched") return "LeftHand.Ring.1 Stretched";
 | 
						|
            if (n == "Left Ring 2 Stretched") return "LeftHand.Ring.2 Stretched";
 | 
						|
            if (n == "Left Ring 3 Stretched") return "LeftHand.Ring.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Left Little 1 Stretched") return "LeftHand.Little.1 Stretched";
 | 
						|
            if (n == "Left Little 2 Stretched") return "LeftHand.Little.2 Stretched";
 | 
						|
            if (n == "Left Little 3 Stretched") return "LeftHand.Little.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Left Thumb 1 Stretched") return "LeftHand.Thumb.1 Stretched";
 | 
						|
            if (n == "Left Thumb 2 Stretched") return "LeftHand.Thumb.2 Stretched";
 | 
						|
            if (n == "Left Thumb 3 Stretched") return "LeftHand.Thumb.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Left Index Spread") return "LeftHand.Index.Spread";
 | 
						|
            if (n == "Left Middle Spread") return "LeftHand.Middle.Spread";
 | 
						|
            if (n == "Left Ring Spread") return "LeftHand.Ring.Spread";
 | 
						|
            if (n == "Left Little Spread") return "LeftHand.Little.Spread";
 | 
						|
            if (n == "Left Thumb Spread") return "LeftHand.Thumb.Spread";
 | 
						|
 | 
						|
            // Right fingers
 | 
						|
            if (n == "Right Index 1 Stretched") return "RightHand.Index.1 Stretched";
 | 
						|
            if (n == "Right Index 2 Stretched") return "RightHand.Index.2 Stretched";
 | 
						|
            if (n == "Right Index 3 Stretched") return "RightHand.Index.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Right Middle 1 Stretched") return "RightHand.Middle.1 Stretched";
 | 
						|
            if (n == "Right Middle 2 Stretched") return "RightHand.Middle.2 Stretched";
 | 
						|
            if (n == "Right Middle 3 Stretched") return "RightHand.Middle.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Right Ring 1 Stretched") return "RightHand.Ring.1 Stretched";
 | 
						|
            if (n == "Right Ring 2 Stretched") return "RightHand.Ring.2 Stretched";
 | 
						|
            if (n == "Right Ring 3 Stretched") return "RightHand.Ring.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Right Little 1 Stretched") return "RightHand.Little.1 Stretched";
 | 
						|
            if (n == "Right Little 2 Stretched") return "RightHand.Little.2 Stretched";
 | 
						|
            if (n == "Right Little 3 Stretched") return "RightHand.Little.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Right Thumb 1 Stretched") return "RightHand.Thumb.1 Stretched";
 | 
						|
            if (n == "Right Thumb 2 Stretched") return "RightHand.Thumb.2 Stretched";
 | 
						|
            if (n == "Right Thumb 3 Stretched") return "RightHand.Thumb.3 Stretched";
 | 
						|
 | 
						|
            if (n == "Right Index Spread") return "RightHand.Index.Spread";
 | 
						|
            if (n == "Right Middle Spread") return "RightHand.Middle.Spread";
 | 
						|
            if (n == "Right Ring Spread") return "RightHand.Ring.Spread";
 | 
						|
            if (n == "Right Little Spread") return "RightHand.Little.Spread";
 | 
						|
            if (n == "Right Thumb Spread") return "RightHand.Thumb.Spread";
 | 
						|
 | 
						|
            return n;
 | 
						|
        }
 | 
						|
 | 
						|
        public void MultiplyLength(AnimationCurve curve, float mlp)
 | 
						|
        {
 | 
						|
            Keyframe[] keys = curve.keys;
 | 
						|
            for (int i = 0; i < keys.Length; i++)
 | 
						|
            {
 | 
						|
                keys[i].time *= mlp;
 | 
						|
            }
 | 
						|
            curve.keys = keys;
 | 
						|
        }
 | 
						|
 | 
						|
        // Add curves to the AnimationClip for each channel
 | 
						|
        public void SetCurves(ref AnimationClip clip, float maxError, float lengthMlp)
 | 
						|
        {
 | 
						|
            MultiplyLength(curve, lengthMlp);
 | 
						|
            BakerUtilities.ReduceKeyframes(curve, maxError);
 | 
						|
 | 
						|
            // BakerUtilities.SetTangentMode(curve);
 | 
						|
 | 
						|
            clip.SetCurve(string.Empty, typeof(Animator), propertyName, curve);
 | 
						|
        }
 | 
						|
 | 
						|
        // Clear all curves
 | 
						|
        public void Reset()
 | 
						|
        {
 | 
						|
            curve = new AnimationCurve();
 | 
						|
        }
 | 
						|
 | 
						|
        // Record a keyframe for each channel
 | 
						|
        public void SetKeyframe(float time, float[] muscles)
 | 
						|
        {
 | 
						|
            curve.AddKey(time, muscles[muscleIndex]);
 | 
						|
        }
 | 
						|
 | 
						|
        // Add a copy of the first frame to the specified time
 | 
						|
        public void SetLoopFrame(float time)
 | 
						|
        {
 | 
						|
            BakerUtilities.SetLoopFrame(time, curve);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    //Manages the Animation Curves for a single Transform that is a child of the root Transform.
 | 
						|
    [System.Serializable]
 | 
						|
    public class BakerTransform
 | 
						|
    {
 | 
						|
 | 
						|
        public Transform transform; // The Transform component to record
 | 
						|
 | 
						|
        // Animation curves for each channel of the Transform
 | 
						|
        public AnimationCurve
 | 
						|
            posX, posY, posZ,
 | 
						|
            rotX, rotY, rotZ, rotW;
 | 
						|
 | 
						|
        private string relativePath; // Path relative to the root
 | 
						|
        private bool recordPosition; // Should we record the localPosition if the transform?
 | 
						|
        private Vector3 relativePosition;
 | 
						|
        private bool isRootNode;
 | 
						|
        private Quaternion relativeRotation;
 | 
						|
 | 
						|
        // The custom constructor
 | 
						|
        public BakerTransform(Transform transform, Transform root, bool recordPosition, bool isRootNode)
 | 
						|
        {
 | 
						|
            this.transform = transform;
 | 
						|
            this.recordPosition = recordPosition || isRootNode;
 | 
						|
            this.isRootNode = isRootNode;
 | 
						|
 | 
						|
            relativePath = string.Empty;
 | 
						|
#if UNITY_EDITOR
 | 
						|
            relativePath = UnityEditor.AnimationUtility.CalculateTransformPath(transform, root);
 | 
						|
#endif
 | 
						|
 | 
						|
            Reset();
 | 
						|
        }
 | 
						|
 | 
						|
        public void SetRelativeSpace(Vector3 position, Quaternion rotation)
 | 
						|
        {
 | 
						|
            relativePosition = position;
 | 
						|
            relativeRotation = rotation;
 | 
						|
        }
 | 
						|
 | 
						|
        // Add curves to the AnimationClip for each channel
 | 
						|
        public void SetCurves(ref AnimationClip clip)
 | 
						|
        {
 | 
						|
            if (recordPosition)
 | 
						|
            {
 | 
						|
                clip.SetCurve(relativePath, typeof(Transform), "localPosition.x", posX);
 | 
						|
                clip.SetCurve(relativePath, typeof(Transform), "localPosition.y", posY);
 | 
						|
                clip.SetCurve(relativePath, typeof(Transform), "localPosition.z", posZ);
 | 
						|
            }
 | 
						|
 | 
						|
            clip.SetCurve(relativePath, typeof(Transform), "localRotation.x", rotX);
 | 
						|
            clip.SetCurve(relativePath, typeof(Transform), "localRotation.y", rotY);
 | 
						|
            clip.SetCurve(relativePath, typeof(Transform), "localRotation.z", rotZ);
 | 
						|
            clip.SetCurve(relativePath, typeof(Transform), "localRotation.w", rotW);
 | 
						|
 | 
						|
            if (isRootNode) AddRootMotionCurves(ref clip);
 | 
						|
 | 
						|
            // @todo probably only need to do it once for the clip
 | 
						|
            clip.EnsureQuaternionContinuity(); // DOH!
 | 
						|
        }
 | 
						|
 | 
						|
        private void AddRootMotionCurves(ref AnimationClip clip)
 | 
						|
        {
 | 
						|
            if (recordPosition)
 | 
						|
            {
 | 
						|
                clip.SetCurve("", typeof(Animator), "MotionT.x", posX);
 | 
						|
                clip.SetCurve("", typeof(Animator), "MotionT.y", posY);
 | 
						|
                clip.SetCurve("", typeof(Animator), "MotionT.z", posZ);
 | 
						|
            }
 | 
						|
 | 
						|
            clip.SetCurve("", typeof(Animator), "MotionQ.x", rotX);
 | 
						|
            clip.SetCurve("", typeof(Animator), "MotionQ.y", rotY);
 | 
						|
            clip.SetCurve("", typeof(Animator), "MotionQ.z", rotZ);
 | 
						|
            clip.SetCurve("", typeof(Animator), "MotionQ.w", rotW);
 | 
						|
        }
 | 
						|
 | 
						|
        // Clear all curves
 | 
						|
        public void Reset()
 | 
						|
        {
 | 
						|
            posX = new AnimationCurve();
 | 
						|
            posY = new AnimationCurve();
 | 
						|
            posZ = new AnimationCurve();
 | 
						|
 | 
						|
            rotX = new AnimationCurve();
 | 
						|
            rotY = new AnimationCurve();
 | 
						|
            rotZ = new AnimationCurve();
 | 
						|
            rotW = new AnimationCurve();
 | 
						|
        }
 | 
						|
 | 
						|
        public void ReduceKeyframes(float maxError)
 | 
						|
        {
 | 
						|
            BakerUtilities.ReduceKeyframes(rotX, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(rotY, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(rotZ, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(rotW, maxError);
 | 
						|
 | 
						|
            BakerUtilities.ReduceKeyframes(posX, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(posY, maxError);
 | 
						|
            BakerUtilities.ReduceKeyframes(posZ, maxError);
 | 
						|
        }
 | 
						|
 | 
						|
        // Record a keyframe for each channel
 | 
						|
        public void SetKeyframes(float time)
 | 
						|
        {
 | 
						|
            if (recordPosition)
 | 
						|
            {
 | 
						|
                Vector3 pos = transform.localPosition;
 | 
						|
 | 
						|
                if (isRootNode)
 | 
						|
                {
 | 
						|
                    pos = transform.position - relativePosition;
 | 
						|
                }
 | 
						|
 | 
						|
                posX.AddKey(time, pos.x);
 | 
						|
                posY.AddKey(time, pos.y);
 | 
						|
                posZ.AddKey(time, pos.z);
 | 
						|
            }
 | 
						|
 | 
						|
            Quaternion rot = transform.localRotation;
 | 
						|
 | 
						|
            if (isRootNode)
 | 
						|
            {
 | 
						|
                rot = Quaternion.Inverse(relativeRotation) * transform.rotation;
 | 
						|
            }
 | 
						|
 | 
						|
            rotX.AddKey(time, rot.x);
 | 
						|
            rotY.AddKey(time, rot.y);
 | 
						|
            rotZ.AddKey(time, rot.z);
 | 
						|
            rotW.AddKey(time, rot.w);
 | 
						|
        }
 | 
						|
 | 
						|
        // Add a copy of the first frame to the specified time
 | 
						|
        public void AddLoopFrame(float time)
 | 
						|
        {
 | 
						|
            // TODO change to SetLoopFrame
 | 
						|
            if (recordPosition && !isRootNode)
 | 
						|
            {
 | 
						|
                posX.AddKey(time, posX.keys[0].value);
 | 
						|
                posY.AddKey(time, posY.keys[0].value);
 | 
						|
                posZ.AddKey(time, posZ.keys[0].value);
 | 
						|
            }
 | 
						|
 | 
						|
            rotX.AddKey(time, rotX.keys[0].value);
 | 
						|
            rotY.AddKey(time, rotY.keys[0].value);
 | 
						|
            rotZ.AddKey(time, rotZ.keys[0].value);
 | 
						|
            rotW.AddKey(time, rotW.keys[0].value);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 |