Unity自动切割动画

最近在开发项目时,需要处理大量的动画,于是就网上查找资料,然后写了这么编辑器工具:

就是在模型导入时,根据配置文件自动切割动画。

首先我们需要封装两个类:一个模型类和一个动画类

 1 public class ModelFbx
 2 {
 3     #region -- 变量定义
 4     public string modelName;    //模型名称
 5     public Clip[] clips;        //模型所包含的动画
 6     #endregion
 7 }
 8 
 9 public class Clip
10 {
11     #region -- 变量定义
12     public string clipName;     //动画名称
13     public int firstFrame;      //动画第一帧
14     public int lastFrame;       //动画最后一帧
15     public bool isLoop;         //是否循环
16     #endregion
17 
18     #region -- 自定义函数
19     /// <summary>
20     /// 构造动画信息
21     /// </summary>
22     /// <param name="_clipName">动画名称</param>
23     /// <param name="_firstFrame">动画第一帧</param>
24     /// <param name="_lastFrame">动画最后一帧</param>
25     /// <param name="_isLoop">动画是否循环</param>
26     public Clip(string _clipName, int _firstFrame, int _lastFrame, bool _isLoop)
27     {
28         clipName = _clipName;
29         firstFrame = _firstFrame;
30         lastFrame = _lastFrame;
31         isLoop = _isLoop;
32     }
33     #endregion
34 
35 }

然后我们封装一个类,来读取配置文件并初始化切割信息的类

  1 using UnityEngine;
  2 using System.Collections.Generic;
  3 using System.Xml;
  4 using System.IO;
  5 
  6 public static class AnimationClipConfig
  7 {
  8     #region -- 变量定义
  9     public static string ConfigPath = "/_Scripts/Editor/CutAnimation/Config.xml";
 10     private static bool mIsInit = false;//配置信息是否初始化
 11     public static List<ModelFbx> modelList = new List<ModelFbx>();
 12     #endregion
 13 
 14     #region -- 自定义函数
 15     public static bool Enable
 16     {
 17         get
 18         {
 19             string _enable = Read(Application.dataPath + ConfigPath, new string[] { "Root", "Enable" });
 20             return bool.Parse(_enable);
 21         }
 22     }
 23     /// <summary>
 24     /// 初始化配置信息
 25     /// </summary>
 26     /// <returns>返回初始化是否成功</returns>
 27     public static bool Init()
 28     {
 29         if (mIsInit)
 30         {
 31             return true;
 32         }
 33         mIsInit = true;
 34 
 35         return InitModeList();
 36     }
 37     private static bool InitModeList()
 38     {
 39         string _path = Application.dataPath + ConfigPath;
 40         if (File.Exists(_path))
 41         {
 42             XmlDocument _xmlDoc = new XmlDocument();
 43             XmlReaderSettings _set = new XmlReaderSettings();
 44             _set.IgnoreComments = true;
 45             XmlReader _reader = XmlReader.Create(_path, _set);
 46             _xmlDoc.Load(_reader);
 47             _reader.Close();
 48             XmlNodeList _nodeList = _xmlDoc.SelectSingleNode("Root").ChildNodes;
 49             foreach (XmlElement _xe in _nodeList)
 50             {
 51                 if (_xe.Name == "ModelFbx")
 52                 {
 53                     ModelFbx _modelFbx = new ModelFbx();
 54                     foreach (XmlElement _x1 in _xe.ChildNodes)
 55                     {
 56                         if (_x1.Name == "ModelName")
 57                         {
 58                             _modelFbx.modelName = _x1.InnerText;
 59                         }
 60                         if (_x1.Name == "Clips")
 61                         {
 62                             _modelFbx.clips = new Clip[_x1.ChildNodes.Count];
 63                             int _index = 0;
 64                             foreach (XmlElement _x2 in _x1.ChildNodes)
 65                             {
 66                                 string _clipName = "";
 67                                 int _firstFrame = 0;
 68                                 int _lastFrame = 0;
 69                                 bool _isLoop = false;
 70                                 foreach (XmlElement _x3 in _x2.ChildNodes)
 71                                 {
 72                                     if (_x3.Name == "ClipName")
 73                                     {
 74                                         _clipName = _x3.InnerText;
 75                                     }
 76                                     if (_x3.Name == "FirstFrame")
 77                                     {
 78                                         _firstFrame = int.Parse(_x3.InnerText);
 79                                     }
 80                                     if (_x3.Name == "LastFrame")
 81                                     {
 82                                         _lastFrame = int.Parse(_x3.InnerText);
 83                                     }
 84                                     if (_x3.Name == "IsLoop")
 85                                     {
 86                                         _isLoop = bool.Parse(_x3.InnerText);
 87                                     }
 88                                 }
 89                                 _modelFbx.clips[_index] = new Clip(_clipName, _firstFrame, _lastFrame, _isLoop);
 90                                 _index++;
 91                             }
 92                         }
 93                     }
 94                     modelList.Add(_modelFbx);
 95                 }
 96             }
 97             return true;
 98         }
 99         else
100         {
101             Debug.LogError("无法找打" + _path + "文件,请检查配置文件路径(ConfigPath)是否正确");
102             return false;
103         }
104     }
105 
106     /// <summary>
107     /// 读取 XML 文件指定子节点数据
108     /// </summary>
109     /// <param name="_path">文件读取路径</param>
110     /// <param name="_xmlNodes">节点数组</param>
111     /// <returns></returns>
112     private static string Read(string _path, string[] _xmlNodes)
113     {
114         string _innerstr = "";//返回值
115         XmlDocument _xmlDoc = new XmlDocument();
116         XmlReaderSettings _set = new XmlReaderSettings();
117         _set.IgnoreComments = true;
118         //判断文件是否存在
119         if (File.Exists(_path))
120         {
121             _xmlDoc.Load(XmlReader.Create(_path, _set));
122         }
123         else
124         {
125             Debug.LogError("目标文件不存在,请检查路径是否有误");
126             return null;
127         }
128         int _nodeNum = _xmlNodes.Length;
129         int _counter = 1;
130         XmlNodeList _nodelist = _xmlDoc.SelectSingleNode(_xmlNodes[0]).ChildNodes;
131         if (_nodelist == null)
132         {
133             return _innerstr;
134         }
135         while (_counter < _nodeNum)
136         {
137             bool _checkok = false;
138             foreach (XmlNode _element in _nodelist)
139             {
140                 if (_element.Name == _xmlNodes[_counter])
141                 {
142                     _checkok = true;
143                     _counter++;
144                     if (_counter >= _nodeNum)
145                     {
146                         _innerstr = _element.InnerText;
147                         _nodelist = null;
148                         break;
149                     }
150                     _nodelist = _element.ChildNodes;
151                     break;
152                 }
153             }
154             if (!_checkok)
155             {
156                 break;
157             }
158         }
159         return _innerstr;
160     }
161     #endregion
162 
163 }

接下来就是切割动画了

using UnityEngine;
using UnityEditor;

public class CutAnimation : AssetPostprocessor
{
    #region -- 系统函数
    /// <summary>
    /// 模型导入之前调用
    /// </summary>
    public void OnPreprocessModel()
    {
        //是否启用动画切割
        if (!AnimationClipConfig.Enable)
        {
            return;
        }

        //当前正在导入的模型
        ModelImporter _modelImporter = (ModelImporter)assetImporter;

        if (AnimationClipConfig.Init())
        {
            foreach (ModelFbx item in AnimationClipConfig.modelList)
            {
                //当前导入模型的路径包含AnimationClipConfig.modelList数据表中的模型名字,那就要对这个模型的动画进行切割  
                if (assetPath.Contains(item.modelName))
                {
                    _modelImporter.animationType = ModelImporterAnimationType.Generic;
                    _modelImporter.generateAnimations = ModelImporterGenerateAnimations.GenerateAnimations;
                    ModelImporterClipAnimation[] _animations = new ModelImporterClipAnimation[item.clips.Length];
                    for (int i = 0; i < item.clips.Length; i++)
                    {
                        _animations[i] = SetClipAnimation(item.clips[i].clipName, item.clips[i].firstFrame, item.clips[i].lastFrame, item.clips[i].isLoop);
                    }
                    _modelImporter.clipAnimations = _animations;
                }
            }
        }
        else
        {
            Debug.LogError("无法找打" + Application.dataPath+AnimationClipConfig.ConfigPath + "文件,请检查配置文件路径(mCofigPath)是否正确");
        }
    }
    #endregion

    #region -- 自定义函数
    private ModelImporterClipAnimation SetClipAnimation(string _clipName, int _firstFrame, int _lastFrame, bool _isLoop)
    {
        ModelImporterClipAnimation _clip = new ModelImporterClipAnimation();
        _clip.name = _clipName;
        _clip.firstFrame =_firstFrame;
        _clip.lastFrame = _lastFrame;
        _clip.loop = _isLoop;
        if (_isLoop)
        {
            _clip.wrapMode = WrapMode.Loop;
        }
        else
        {
            _clip.wrapMode = WrapMode.Default;
        }
        return _clip;
    }
    #endregion

}

感觉也没啥好说的,就直接分享代码了。而且我觉得这个功能比较鸡肋,适用性不是很广,只能在一些特定情况下用到。

下面是我的配置文件和文件结构:

<?xml version="1.0" encoding="utf-8"?>

<Root>
  <Enable>True</Enable><!--是否启用。启用:True;禁用:False-->
  
  <ModelFbx><!--模型-->
    <ModelName>1</ModelName><!--模型名称(string)-->
    <Clips><!--动画集-->
      <Clip><!--动画-->
        <ClipName>Start</ClipName><!--动画名称(string)-->
        <FirstFrame>0</FirstFrame><!--动画第一帧(int)-->
        <LastFrame>1</LastFrame><!--动画最后一帧(int)-->
        <IsLoop>False</IsLoop><!--是否循环(bool)-->
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips> 
  </ModelFbx>

  <ModelFbx>
    <ModelName>2</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>3</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>4</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>5</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>6</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>7</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>8</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>9</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>10</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>

  <ModelFbx>
    <ModelName>11</ModelName>
    <Clips>
      <Clip>
        <ClipName>Start</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>1</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>Take</ClipName>
        <FirstFrame>0</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>

      <Clip>
        <ClipName>End</ClipName>
        <FirstFrame>149</FirstFrame>
        <LastFrame>150</LastFrame>
        <IsLoop>False</IsLoop>
      </Clip>
    </Clips>
  </ModelFbx>
  
</Root>
原文地址:https://www.cnblogs.com/xiaoyulong/p/9848132.html