コード例 #1
0
        void OnGUI()
        {
            EditorGUI.BeginChangeCheck();
            m_Clip     = (AnimationClip)EditorGUILayout.ObjectField("Compress clip:", m_Clip, typeof(AnimationClip), false);
            m_PosErr   = EditorGUILayout.FloatField(new GUIContent("Position Threshold:", "raising this value could reduce more keys"), m_PosErr);
            m_RotErr   = EditorGUILayout.FloatField(new GUIContent("Rotation Threshold:", "raising this value could reduce more keys"), m_RotErr);
            m_ScaErr   = EditorGUILayout.FloatField(new GUIContent("Scale Threshold:", "raising this value could reduce more keys"), m_ScaErr);
            m_FloatErr = EditorGUILayout.FloatField(new GUIContent("Float Threshold:", "raising this value could reduce more keys"), m_FloatErr);
            m_Verbose  = EditorGUILayout.ToggleLeft("Verbose", m_Verbose);
            if (EditorGUI.EndChangeCheck())
            {
            }

            EUtil.PushGUIEnable(m_Clip != null);
            if (EUtil.Button("Execute!", "Start the work", Color.green, GUILayout.ExpandHeight(true)))
            {
                string newPath = EditorUtility.SaveFilePanelInProject("Save new clip", m_Clip.name + "_optimized", "anim", "Select new optimized clip save location");
                if (!string.IsNullOrEmpty(newPath))
                {
                    string oldPath = AssetDatabase.GetAssetPath(m_Clip);
                    if (oldPath == newPath)
                    {
                        bool bOK = EditorUtility.DisplayDialog("Are you sure?", "You're going to overwrite old animation file", "Go Ahead", "No-No");
                        if (bOK)
                        {
                            var comp = new AnimCompress();
                            comp.Verbose = m_Verbose;
                            comp.ReduceKeyframes(m_Clip, m_PosErr, m_RotErr, m_ScaErr, m_FloatErr);
                        }
                    }
                    else
                    {
                        AnimationClip newClip = AnimationClip.Instantiate(m_Clip) as AnimationClip;
                        if (newClip == null)
                        {
                            Dbg.LogErr("cannot load new clip at path: {0}", newPath);
                            return;
                        }
                        var comp = new AnimCompress();
                        comp.Verbose = m_Verbose;
                        comp.ReduceKeyframes(newClip, m_PosErr, m_RotErr, m_ScaErr, m_FloatErr);

                        newClip.name = Path.GetFileNameWithoutExtension(newPath);
                        EUtil.SaveAnimClip(newClip, newPath);
                    }
                }
            }
            EUtil.PopGUIEnable();
        }
コード例 #2
0
    // public method

    #endregion "public method"

    #region "private method"
    // private method

    private void _ConvertAnim(string newClipAssetPath)
    {
        // 0. prepare
        if (!m_Animator.isHuman)
        {
            Dbg.LogWarn("MuscleClipConverterEditor._ConvertAnim: Need to change to Humanoid rig first!");
            return;
        }

        m_SMR = m_Animator.GetComponentInChildren <SkinnedMeshRenderer>();
        if (m_SMR == null)
        {
            Dbg.LogWarn("MuscleClipConverterEditor._ConvertAnim: failed to find SMR under {0}", m_Animator.name);
            return;
        }

        m_Animator.Update(0);
#if !U5
        var ainfos = m_Animator.GetCurrentAnimationClipState(0); //only effect after Update is called
#else
        var ainfos = m_Animator.GetCurrentAnimatorClipInfo(0);   //only effect after Update is called
#endif
        AnimationClip         clip        = ainfos[0].clip;
        AnimationClipSettings clipSetting = AnimationUtility.GetAnimationClipSettings(clip);

        //{//debug
        //    var bindings = AnimationUtility.GetCurveBindings(clip);
        //    foreach( var b in bindings)
        //    {
        //        Dbg.Log("path: {0}, prop: {1}", b.path, b.propertyName);
        //    }
        //}

        Transform animatorTr = m_Animator.transform;
        Transform hipsBone   = null;
        CurveDict curveDict  = new CurveDict();

        float SAMPLE_RATE = clip.frameRate;
        float clipLen     = clip.length;

        Matrix4x4 animatorInitW2LMat = animatorTr.worldToLocalMatrix;
        Matrix4x4 hipsInitW2LMat     = Matrix4x4.identity;

        List <Transform> boneLst = new List <Transform>();
        for (HumanBodyBones boneIdx = 0; boneIdx < HumanBodyBones.LastBone; ++boneIdx)
        {
            Transform tr = m_Animator.GetBoneTransform(boneIdx);
            //Dbg.Log("Map: {0}->{1}", boneIdx, tr);
            if (tr != null)
            {
                boneLst.Add(tr);
                if (boneIdx == HumanBodyBones.Hips)
                {
                    hipsBone       = tr;
                    hipsInitW2LMat = hipsBone.parent.worldToLocalMatrix;
                    //clipSetting.level = -hipsBone.localPosition.y; // set Y offset
                    clipSetting.keepOriginalPositionY = false; //use RootNode position
                }
            }
        }
        Transform[] bones = boneLst.ToArray();

        // init curves for each bone
        for (int idx = 0; idx < bones.Length; ++idx)
        {
            Transform oneBone = bones[idx];
            string    trPath  = AnimationUtility.CalculateTransformPath(oneBone, animatorTr);

            var curves = new _Curves();
            curves.relPath = trPath;

            curveDict.Add(oneBone, curves);
        }

        // init rootmotion curve
        {
            var curves = new _Curves();
            curveDict.Add(animatorTr, curves);
        }

        AnimatorStateInfo curStateInfo = m_Animator.GetCurrentAnimatorStateInfo(0);
        float             nt           = curStateInfo.normalizedTime;
        m_Animator.Update(-nt * clipLen); //revert to 0 time

        {                                 // 1. bake animation info into curve on all bones transform
            float time      = 0f;
            float deltaTime = 1f / (SAMPLE_RATE);
            for (;
                 time <= clipLen || Mathf.Approximately(time, clipLen);
                 )
            {
                //Dbg.Log("nt = {0}", m_Animator.GetCurrentAnimatorStateInfo(0).normalizedTime);

                // bone
                for (int idx = 0; idx < bones.Length; ++idx)
                {
                    Transform oneBone = bones[idx];
                    _Curves   curves  = curveDict[oneBone];

                    if (oneBone == hipsBone)
                    {
                        continue; //skip the HipsBone. This is to add rootMotion matrix on hips, so Legacy is right
                    }
                    Vector3    pos = oneBone.localPosition;
                    Quaternion rot = oneBone.localRotation;

                    curves.X.AddKey(time, rot.x);
                    curves.Y.AddKey(time, rot.y);
                    curves.Z.AddKey(time, rot.z);
                    curves.W.AddKey(time, rot.w);

                    curves.PX.AddKey(time, pos.x);
                    curves.PY.AddKey(time, pos.y);
                    curves.PZ.AddKey(time, pos.z);
                }

                // root motion process
                {
                    { //on Animator transform
                        Vector3 pos = /*animatorTr.localPosition*/ animatorTr.position;
                        Vector3 fwd = animatorTr.forward;
                        Vector3 up  = animatorTr.up;

                        _Curves rootMotionCurves = curveDict[animatorTr];
                        Vector3 lpos             = animatorInitW2LMat.MultiplyPoint(pos);
                        Vector3 lfwd             = animatorInitW2LMat.MultiplyVector(fwd);
                        Vector3 lup = animatorInitW2LMat.MultiplyVector(up);

                        Quaternion rot = Quaternion.LookRotation(lfwd, lup);

                        rootMotionCurves.X.AddKey(time, rot.x);
                        rootMotionCurves.Y.AddKey(time, rot.y);
                        rootMotionCurves.Z.AddKey(time, rot.z);
                        rootMotionCurves.W.AddKey(time, rot.w);

                        rootMotionCurves.PX.AddKey(time, lpos.x);
                        rootMotionCurves.PY.AddKey(time, lpos.y);
                        rootMotionCurves.PZ.AddKey(time, lpos.z);
                    }

                    { //on hips transform
                        if (hipsBone != null)
                        {
                            Vector3 pos = hipsBone.position;
                            Vector3 fwd = hipsBone.forward;
                            Vector3 up  = hipsBone.up;

                            _Curves hipsCurves = curveDict[hipsBone];
                            Vector3 lpos       = hipsInitW2LMat.MultiplyPoint(pos);
                            Vector3 lfwd       = hipsInitW2LMat.MultiplyVector(fwd);
                            Vector3 lup        = hipsInitW2LMat.MultiplyVector(up);

                            //Dbg.Log("time: {0}, lpos: {1}", time, lpos.ToString("F2"));

                            Quaternion rot = Quaternion.LookRotation(lfwd, lup);

                            hipsCurves.X.AddKey(time, rot.x);
                            hipsCurves.Y.AddKey(time, rot.y);
                            hipsCurves.Z.AddKey(time, rot.z);
                            hipsCurves.W.AddKey(time, rot.w);

                            hipsCurves.PX.AddKey(time, lpos.x);
                            hipsCurves.PY.AddKey(time, lpos.y);
                            hipsCurves.PZ.AddKey(time, lpos.z);
                        }
                    }
                }

                if (!Mathf.Approximately(time + deltaTime, clipLen))
                {
                    m_Animator.Update(deltaTime);
                    time += deltaTime;
                }
                else
                {
                    m_Animator.Update(deltaTime - 0.005f); //keep it in the range, if go beyond, something bad could happen
                    time += deltaTime - 0.005f;
                }
            }
        } //end of 1.


        { // 2. set animation clip and store in AssetDatabase
            AnimationClip newClip = new AnimationClip();
            newClip.frameRate   = SAMPLE_RATE;
            newClip.localBounds = clip.localBounds;

            // set bone curves
            for (var ie = curveDict.GetEnumerator(); ie.MoveNext();)
            {
                var curves = ie.Current.Value;
                if (ie.Current.Key == animatorTr)
                { //root motion
                    newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.x", curves.PX);
                    newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.y", curves.PY);
                    newClip.SetCurve(curves.relPath, typeof(Animator), "MotionT.z", curves.PZ);

                    newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.x", curves.X);
                    newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.y", curves.Y);
                    newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.z", curves.Z);
                    newClip.SetCurve(curves.relPath, typeof(Animator), "MotionQ.w", curves.W);
                }
                else
                {
                    newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.x", curves.X);
                    newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.y", curves.Y);
                    newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.z", curves.Z);
                    newClip.SetCurve(curves.relPath, typeof(Transform), "localRotation.w", curves.W);

                    newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.x", curves.PX);
                    newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.y", curves.PY);
                    newClip.SetCurve(curves.relPath, typeof(Transform), "localPosition.z", curves.PZ);
                }
            }

            // 2.1 copy the unmapped curves to new clip( not mapped by Muscle clip )
            _CopyOtherCurves(newClip, clip);

            // some setting work
            newClip.EnsureQuaternionContinuity();

#if !U5
            AnimationUtility.SetAnimationType(newClip, m_AnimType);
            RCall.CallMtd("UnityEditor.AnimationUtility", "SetAnimationClipSettings", null, newClip, clipSetting);
#else
            if (m_AnimType == ModelImporterAnimationType.Legacy)
            {
                newClip.legacy = true;
            }
            AnimationUtility.SetAnimationClipSettings(newClip, clipSetting);
#endif

            EUtil.SaveAnimClip(newClip, newClipAssetPath);

            EUtil.ShowNotification("Converted to: " + m_AnimType +
                                   (hipsBone != null ? ("\nroot=" + AnimationUtility.CalculateTransformPath(hipsBone, animatorTr)) : ""),
                                   3f
                                   );
        } //end of 2.

        // 3. clean job
        curveDict = null;
        AssetDatabase.SaveAssets();

        Dbg.Log("Converted: {0}", newClipAssetPath);
    }