UnityEditor tool_Manually generate animation clips and data

Function

When running, record information of the selected object with one key and save it to the animation, which can continuously record the movement of the object.

train of thought

Select the object, create an animationclip, traverse and obtain all sub-objects of the object, record the position and rotation of each object (additional data can be added), and write the current data into the clip. When used multiple times, it is judged whether there is a corresponding clip, and the frame number is added backwards. Animate.

Problem: Handedness may not be as expected. Solution: After selecting the clip, modify the difference method of all rotation attributes (right click on the rotation to modify the interpolation). ps: I haven't found how to change the code yet, so I can only change it manually

function points

  1. To write data in the clip, you need to know the complete path (obtain the path of all objects under the object):
    the idea here is: the path under the object has the repetition of the upper path, here use layer order traversal, and then get the path (I don’t know efficiency has improved).
    Direct way of thinking: Find the path directly for each object and traverse it once.
  2. The operation of writing data to clip
  3. Continuously write data to clip

accomplish

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class CreateAnimationHelperEditor : Editor
{
    
    
    private static float addFrame = 0.5f;

    static List<Transform> needTrans = new List<Transform>();
    static Queue<Transform> queue = new Queue<Transform>();
    static string[] pathss;
    [MenuItem("追踪数据生成动画/为GameObject创建空Clip[仅根物体]")]
    public static void CreateEmptyAnimationClip()
    {
    
    
        GameObject obj = Selection.activeObject as GameObject;

        string clipFilePath = "Assets/" + obj.name + "_create.anim";

        //遍历物体下的子物体
        //每一个物体,获取路径,名称
        TreeSortLayer(obj.transform);

        //查找是否以及生成clip
        AnimationClip createClip = AssetDatabase.LoadAssetAtPath<AnimationClip>(clipFilePath);

        if (createClip == null)
        {
    
    
            //创建clip
            createClip = new AnimationClip();
            createClip.legacy = true;
            AnimationCurve[] acs = new AnimationCurve[7];
           
            for (int i = 0; i < needTrans.Count; i++)
            {
    
    
                for (int y = 0; y < acs.Length; y++)
                {
    
    
                    acs[y] = new AnimationCurve();
                }
                //动画帧数据
                Vector3 pos = needTrans[i].localPosition;
                Quaternion rot = Quaternion.Euler(needTrans[i].localEulerAngles);
                acs[0].AddKey(0, pos.x);
                acs[1].AddKey(0, pos.y);
                acs[2].AddKey(0, pos.z);

                //acs[3].AddKey(0, rot.eulerAngles.x);
                //acs[4].AddKey(0, rot.eulerAngles.y);
                //acs[5].AddKey(0, rot.eulerAngles.z);


                acs[3].AddKey(0, rot.x);
                acs[4].AddKey(0, rot.y);
                acs[5].AddKey(0, rot.z);
                acs[6].AddKey(0, rot.w);

                //给clip添加曲线(自动生成EditorCurveBinding)
                createClip.SetCurve(pathss[i], typeof(Transform), "m_LocalPosition.x", acs[0]);
                createClip.SetCurve(pathss[i], typeof(Transform), "m_LocalPosition.y", acs[1]);
                createClip.SetCurve(pathss[i], typeof(Transform), "m_LocalPosition.z", acs[2]);
                createClip.SetCurve(pathss[i], typeof(Transform), "m_LocalRotation.x", acs[3]);
                createClip.SetCurve(pathss[i], typeof(Transform), "m_LocalRotation.y", acs[4]);
                createClip.SetCurve(pathss[i], typeof(Transform), "m_LocalRotation.z", acs[5]);
                createClip.SetCurve(pathss[i], typeof(Transform), "m_LocalRotation.w", acs[6]);
            }
            createClip.EnsureQuaternionContinuity();
            AnimationCurve ac = new AnimationCurve();

            AnimationClipSettings acttt = new AnimationClipSettings();
            //acttt.loopBlendOrientation

            
            AssetDatabase.CreateAsset(createClip, clipFilePath);

            EditorGUIUtility.PingObject(createClip);
        }
        else
        {
    
    
            List<string> strPath = new List<string>(pathss);
            
            //获取curver
            EditorCurveBinding[] binds = AnimationUtility.GetCurveBindings(createClip);
            for(int i = 0; i < binds.Length; i++)
            {
    
    
              
                AnimationCurve ac = AnimationUtility.GetEditorCurve(createClip, binds[i]);

                Debug.Log(ac.length);
                //找物体对应部位
                int count = strPath.FindIndex(p => p == binds[i].path);

                switch (binds[i].propertyName)
                {
    
    
                    case "m_LocalPosition.x":
                        ac.AddKey((float)ac.length * addFrame, needTrans[count].localPosition.x);
                        break;
                    case "m_LocalPosition.y":
                        ac.AddKey((float)ac.length * addFrame, needTrans[count].localPosition.y);
                        break;
                    case "m_LocalPosition.z":
                        ac.AddKey((float)ac.length * addFrame, needTrans[count].localPosition.z);
                        break;
                    case "m_LocalRotation.x":
                        ac.AddKey((float)ac.length * addFrame, needTrans[count].localRotation.x);
                        break;
                    case "m_LocalRotation.y":
                        ac.AddKey((float)ac.length * addFrame, needTrans[count].localRotation.y);
                        break;
                    case "m_LocalRotation.z":
                        ac.AddKey((float)ac.length * addFrame, needTrans[count].localRotation.z);
                        break;
                    case "m_LocalRotation.w":
                        ac.AddKey((float)ac.length * addFrame, needTrans[count].localRotation.w);
                        break;
                }


                AnimationUtility.SetEditorCurve(createClip, binds[i], ac);
            }
            EditorGUIUtility.PingObject(createClip);
        }
    }


    [MenuItem("追踪数据生成动画/测试_物体路径打印")]
    public static void TestFunc()
    {
    
    
        GameObject obj = Selection.activeObject as GameObject;

        TreeSortLayer(obj.transform);

        foreach(var x in pathss)
        {
    
    
            Debug.Log(x);
        }
    }

    [MenuItem("追踪数据生成动画/测试_打印动画路径")]
    public static void AnimaShow()
    {
    
    
        GameObject obj = Selection.activeObject as GameObject;
        //Animation objAni = obj.GetComponent<Animation>();
        AnimationClip[] acs = AnimationUtility.GetAnimationClips(obj);
        for(int i = 0; i < acs.Length; i++)
        {
    
    
            AnimationClip ac = acs[i];
            Debug.Log(ac.name);
            EditorCurveBinding[] ecbs = AnimationUtility.GetCurveBindings(ac);
            for(int m = 0; m < ecbs.Length; m++)
            {
    
    
                AnimationCurve acc = AnimationUtility.GetEditorCurve(ac, ecbs[m]);
                string str = string.Format("【{0}】/【{1}】/【{2}】", ecbs[m].path, ecbs[m].propertyName, acc.keys[0].value);
                Debug.Log(str);
            }
        }
    }



  

    //层序遍历物体 记录每层
    private static void TreeSortLayer(Transform obj)
    {
    
    
        queue.Clear();
        needTrans.Clear();
        pathss = null;
        queue.Enqueue(obj);
        Que(queue);

        //获取路径
        pathss = new string[needTrans.Count];
        int nowObj =0 ;
        for (int i = 0; i < needTrans.Count; i++)
        {
    
    
            //第一个
            if (i == 0)
            {
    
    
                //pathss[i] = needTrans[i].name;
                pathss[i] = "";
                nowObj = i;
                continue;
            }
            //当前是父物体
            if(needTrans[i].parent == needTrans[nowObj])
            {
    
    
                if (nowObj == 0)
                {
    
    
                    pathss[i] = needTrans[i].name;
                }
                else
                {
    
    
                    pathss[i] = pathss[nowObj] + "/" + needTrans[i].name;
                }
               
            }
            else
            {
    
    
                //nowObj++;
                //找到父物体
                nowObj = needTrans.FindIndex(nowObj,i-nowObj, p => p == needTrans[i].parent);
                pathss[i] = pathss[nowObj] + "/" + needTrans[i].name;
            }
        }
    }


    private static void Que(Queue<Transform> que)
    {
    
    
        //obj in
        while (que.Count > 0)
        {
    
    
            //out (needdata)
            Transform obj = que.Dequeue();
            needTrans.Add(obj);

            //in
            for (int i = 0; i < obj.childCount; i++)
            {
    
    
                que.Enqueue(obj.GetChild(i));
            }
        }
    }


}

Guess you like

Origin blog.csdn.net/suixinger_lmh/article/details/125094437