zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    Lambda表达式 For Android
    RxJava重温基础
    Asp.Net Core 依赖注入默认DI,Autofac注入
    Asp.Net Core2.0 基于QuartzNet任务管理系统
    Asp.Net Core 基于QuartzNet任务管理系统(这是一篇用来水的随笔)
    ADO.NET通用类库
    TripleDES加密解密
    ASP.NET Core的身份认证框架IdentityServer4--(4)添加第三方快捷登录
    ASP.NET Core的身份认证框架IdentityServer4--(3)令牌服务配置访问控制跟UI(可自定义路由)添加
    ASP.NET Core的身份认证框架IdentityServer4--(2)API跟WEB端配置
  • 原文地址:https://www.cnblogs.com/xiaoyulong/p/9848132.html
Copyright © 2011-2022 走看看