Unity自动切割动画
最近在开发项目时,需要处理大量的动画,于是就网上查找资料,然后写了这么编辑器工具:
就是在模型导入时,根据配置文件自动切割动画。
首先我们需要封装两个类:一个模型类和一个动画类
public class ModelFbx
{
#region -- 变量定义
public string modelName; //模型名称
public Clip[] clips; //模型所包含的动画
#endregion
} public class Clip
{
#region -- 变量定义
public string clipName; //动画名称
public int firstFrame; //动画第一帧
public int lastFrame; //动画最后一帧
public bool isLoop; //是否循环
#endregion #region -- 自定义函数
/// <summary>
/// 构造动画信息
/// </summary>
/// <param name="_clipName">动画名称</param>
/// <param name="_firstFrame">动画第一帧</param>
/// <param name="_lastFrame">动画最后一帧</param>
/// <param name="_isLoop">动画是否循环</param>
public Clip(string _clipName, int _firstFrame, int _lastFrame, bool _isLoop)
{
clipName = _clipName;
firstFrame = _firstFrame;
lastFrame = _lastFrame;
isLoop = _isLoop;
}
#endregion }
然后我们封装一个类,来读取配置文件并初始化切割信息的类
using UnityEngine;
using System.Collections.Generic;
using System.Xml;
using System.IO; public static class AnimationClipConfig
{
#region -- 变量定义
public static string ConfigPath = "/_Scripts/Editor/CutAnimation/Config.xml";
private static bool mIsInit = false;//配置信息是否初始化
public static List<ModelFbx> modelList = new List<ModelFbx>();
#endregion #region -- 自定义函数
public static bool Enable
{
get
{
string _enable = Read(Application.dataPath + ConfigPath, new string[] { "Root", "Enable" });
return bool.Parse(_enable);
}
}
/// <summary>
/// 初始化配置信息
/// </summary>
/// <returns>返回初始化是否成功</returns>
public static bool Init()
{
if (mIsInit)
{
return true;
}
mIsInit = true; return InitModeList();
}
private static bool InitModeList()
{
string _path = Application.dataPath + ConfigPath;
if (File.Exists(_path))
{
XmlDocument _xmlDoc = new XmlDocument();
XmlReaderSettings _set = new XmlReaderSettings();
_set.IgnoreComments = true;
XmlReader _reader = XmlReader.Create(_path, _set);
_xmlDoc.Load(_reader);
_reader.Close();
XmlNodeList _nodeList = _xmlDoc.SelectSingleNode("Root").ChildNodes;
foreach (XmlElement _xe in _nodeList)
{
if (_xe.Name == "ModelFbx")
{
ModelFbx _modelFbx = new ModelFbx();
foreach (XmlElement _x1 in _xe.ChildNodes)
{
if (_x1.Name == "ModelName")
{
_modelFbx.modelName = _x1.InnerText;
}
if (_x1.Name == "Clips")
{
_modelFbx.clips = new Clip[_x1.ChildNodes.Count];
int _index = ;
foreach (XmlElement _x2 in _x1.ChildNodes)
{
string _clipName = "";
int _firstFrame = ;
int _lastFrame = ;
bool _isLoop = false;
foreach (XmlElement _x3 in _x2.ChildNodes)
{
if (_x3.Name == "ClipName")
{
_clipName = _x3.InnerText;
}
if (_x3.Name == "FirstFrame")
{
_firstFrame = int.Parse(_x3.InnerText);
}
if (_x3.Name == "LastFrame")
{
_lastFrame = int.Parse(_x3.InnerText);
}
if (_x3.Name == "IsLoop")
{
_isLoop = bool.Parse(_x3.InnerText);
}
}
_modelFbx.clips[_index] = new Clip(_clipName, _firstFrame, _lastFrame, _isLoop);
_index++;
}
}
}
modelList.Add(_modelFbx);
}
}
return true;
}
else
{
Debug.LogError("无法找打" + _path + "文件,请检查配置文件路径(ConfigPath)是否正确");
return false;
}
} /// <summary>
/// 读取 XML 文件指定子节点数据
/// </summary>
/// <param name="_path">文件读取路径</param>
/// <param name="_xmlNodes">节点数组</param>
/// <returns></returns>
private static string Read(string _path, string[] _xmlNodes)
{
string _innerstr = "";//返回值
XmlDocument _xmlDoc = new XmlDocument();
XmlReaderSettings _set = new XmlReaderSettings();
_set.IgnoreComments = true;
//判断文件是否存在
if (File.Exists(_path))
{
_xmlDoc.Load(XmlReader.Create(_path, _set));
}
else
{
Debug.LogError("目标文件不存在,请检查路径是否有误");
return null;
}
int _nodeNum = _xmlNodes.Length;
int _counter = ;
XmlNodeList _nodelist = _xmlDoc.SelectSingleNode(_xmlNodes[]).ChildNodes;
if (_nodelist == null)
{
return _innerstr;
}
while (_counter < _nodeNum)
{
bool _checkok = false;
foreach (XmlNode _element in _nodelist)
{
if (_element.Name == _xmlNodes[_counter])
{
_checkok = true;
_counter++;
if (_counter >= _nodeNum)
{
_innerstr = _element.InnerText;
_nodelist = null;
break;
}
_nodelist = _element.ChildNodes;
break;
}
}
if (!_checkok)
{
break;
}
}
return _innerstr;
}
#endregion }
接下来就是切割动画了
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 = ; 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></ModelName><!--模型名称(string)-->
<Clips><!--动画集-->
<Clip><!--动画-->
<ClipName>Start</ClipName><!--动画名称(string)-->
<FirstFrame></FirstFrame><!--动画第一帧(int)-->
<LastFrame></LastFrame><!--动画最后一帧(int)-->
<IsLoop>False</IsLoop><!--是否循环(bool)-->
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> <ModelFbx>
<ModelName></ModelName>
<Clips>
<Clip>
<ClipName>Start</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>Take</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip> <Clip>
<ClipName>End</ClipName>
<FirstFrame></FirstFrame>
<LastFrame></LastFrame>
<IsLoop>False</IsLoop>
</Clip>
</Clips>
</ModelFbx> </Root>
Unity自动切割动画的更多相关文章
- Unity自动生成AnimatorController
上一篇写了如何自动切割动画,这一篇写如何自动生成AnimatorController. 之前网上查了很多资料,看的一直很蒙,看不懂是怎么回事的,这里我先给大家明确几个概念: 画的不好,大家将就着看,写 ...
- 关于Unity中Mecanim动画的动画状态代码控制与代码生成动画控制器
对于多量的.复杂的.有规律的控制器使用代码生成 动画状态代码控制 1:每个动画状态,比如进入状态,离开状态, 等都有可能需要代码来参与和处理,比如,进入这个动画单元后做哪些事情,来开这个动画单元后做哪 ...
- Unity 2D骨骼动画2:创建真实动画
http://bbs.9ria.com/thread-401781-1-1.html 在这个系列,我们将关注Unity引擎提供的基于骨骼动画工具.它的主要思想是为了把它应用到你自己的游戏来介绍和教基本 ...
- Unity2D研究院之自动生成动画、AnimationController、Prefab(一)
http://www.xuanyusong.com/archives/3243 国庆了,回家了.时刻还是要吃一颗学习的心,在家了也要抽出时间好好学习一下.之前MOMO一直没研究过Unity2D,今天研 ...
- unity 对Animator动画系统的研究
unity的新动画系统叫Mecanim,使用Animator来取代旧系统Animation,按Unity文档的惯例:知识点主要分2部分:unity manual和unity script,读者可以边看 ...
- Unity MegaFiers 顶点动画
使用 MegaFiers 插件,能够使得Unity支持顶点动画的播放. 官方视频教程例如以下: 在这里简单測试使用下,环境例如以下: Blender 2.72 Unity 4.5.4 Mega ...
- Linux下nginx生成日志自动切割
1.编辑切割日志的 shell 程序,目录自定 #vi /data/nginx/cut_nginx_log.sh 输入代码: #!/bin/bash # This script run at 00:0 ...
- 【shell脚本】nginx每天自动切割日志脚本
nginx每天日志量比较大的时候,最好每天自动切割,存储,这样可以方面以后的查询和分析 #!/bin/sh ################### #filename: nginx_log_rotat ...
- linux系统日志自动切割工具----logrotate
参考资料 :https://www.cnblogs.com/kevingrace/p/6307298.html 对于Linux系统安全来说,日志文件是极其重要的工具.不知为何,我发现很多运维同学的服务 ...
随机推荐
- 好用的截图picpick工具,无需注册,无需破解
链接:https://pan.baidu.com/s/1KtgF2wPdbRXAAenvrPiPzA 提取码:vasu
- c#实现文件写入数据表/以二进制流保存到数据库,并实现下载
上传: 1.上传文件先保存到服务器 File.SaveAs(path) 2.sql(文件和sql在一个服务器上)进行保存操作: insert into File(filename,filebody ...
- linux系统ssh免密钥登录配置
linux主机配置ssh免密钥登录,具体配置如下: 1.执行命令ssh-keygen -t rsa,生成公钥和私钥(具体步骤详见下图) 2.会在当前用户的家目录的.ssh/生成公钥和私钥, 3.执行s ...
- mysql学习笔记--数据库预处理
一.概念 1. 预编译一次,可以多次执行.用来解决一条sql语句频繁执行的问题 2. 语法 a. 预处理语句:preapre 预处理名字 from 'sql语句' b. 执行预处理:execute 预 ...
- chip8模拟器的python3实现-1-CHIP8简介
打算编写一个NES模拟器,先从简单的chip8模拟器入手 1.CHIP-8简介 CHIP-8是一个解释型语言,由Joseph Weisbecker开发.最初CHIP-8在上个世纪70年代被使用在COS ...
- Redis master/slave,sentinel,Cluster简单总结
现在互联网项目中大量使用了redis,本文著主要分析下redis 单点,master/slave,sentinel模式.cluster的一些特点. 一.单节点模式 单节点实例还是比较简单的,平时做个测 ...
- spring :Log4j各级别日志重复打印
使用filter进行日志过滤 这个其实是Log4j自带的方案,也是推荐方案,不知道为什么网上的资料却很少提到这点. 把log4j.properties配置文件修改成如下: #root日志 log4j. ...
- boost asio死锁一例
socket close -> sendmessage -> io_service stop 先关闭socket句柄,再给windows窗口发送消息,然后io_service停止. 当se ...
- 26. pt-summary
pt-summary # Percona Toolkit System Summary Report ###################### Date | 2018-11-23 10:48:51 ...
- Heartbeat详解
转自:http://blog.sina.com.cn/s/blog_7b6fc4c901012om0.html 配置主节点的Heartbeat Heartbeat的主要配置文件有ha.cf.hares ...