Unity插件 - MeshEditor(五) 网格顶点动画(变形动画)
网格顶点动画(变形动画)是针对于物体的形状可以随意变换并记录为关键帧的动画,虽然模型的顶点数据还是应该交给GPU绘制才是正道,CPU刷新模型顶点始终是个吃力不讨好的事(不过我好像至始至终就是在干吃力不讨好的事来着),所以变形动画还是别用到过于复杂的模型之上,毕竟到头来吃力的只会是你的CPU,不过一些简单的模型倒不用担心,像什么旗帜飘扬什么的,不用打开3DMAX(前提是得会用这东西K动画),不用局限于Unity的animator系统(毕竟给你一个做得像旗帜的cube,你能用animator调出一个飘动的动画?),只需简单的几步拖拽便可以K出一个动画,并且可以将动画信息保存为本地文件,实现多项目间复用,同时,顶点数相同的模型也可以复用动画。
传送门(变形动画状态机,变形动画骨骼搭建)
变形动画完全不同于Unity Animator系统的机制,事实上跟它半毛钱关系都没有,所以这两种动画在同一物体上是可以共同存在的,事实上,众所周知,Animator的关键帧只会记录物体的transform组件的position、rotation以及scale的数值变化(当然其他组件的部分属性它也是可以记录的,比如Image的Color),其余的很多属性改变都不会被它视为有另一关键帧产生,而变形动画只会记录模型的顶点数据作为关键帧,完全不会改动transform组件的属性,所以这两种动画完全可以共存。
好了,进入正题,我以给一个cube调节一个变形动画为例子讲解一下整个流程及实现的思路。
第一步:
为cube添加我们的变形动画编辑器组件(MeshAnimation)
添加动画帧:以Scene场景中当前物体的状态信息保存为一个新的关键帧,这里的代码主要是记录每个顶点的位置
/// <summary>/// 添加动画帧/// </summary>public void AddFrame(){Vector3[] vertices = new Vector3[_Vertices.Length];for (int i = 0; i < _Vertices.Length; i++){vertices[i] = _Vertices[i].transform.position;}_VerticesAnimationArray.Add(vertices);}
我们最好先在cube的初始状态就添加一个动画帧,以便于播放动画时它会从初始状态开始
第二步:
现在我们多添加几个关键帧,目前每帧的状态都是保持在初始形态
第三步:
我们的第一帧就让他保持初始状态,现在选中第二帧,同时在场景中调节cube的形态,当你觉得满意的时候,点击apply应用就可以将物体的状态应用到当前的第二帧数据,当然如果这一关键帧不想要了,点击delete删除即可
/// <summary>/// 应用动画帧/// </summary>public void ApplyFrame(){//如果当前动画帧数据存在,则应用当前物体的各顶点数据至当前动画帧if (_NowSelectFrame >= 0 && _NowSelectFrame < _VerticesAnimationArray.Count){for (int i = 0; i < _Vertices.Length; i++){_VerticesAnimationArray[_NowSelectFrame][i] = _Vertices[i].transform.position;}}}
/// <summary>/// 删除动画帧/// </summary>public void DeleteFrame(){//如果当前动画帧数据存在,则删除当前动画帧数据if (_NowSelectFrame >= 0 && _NowSelectFrame < _VerticesAnimationArray.Count){_VerticesAnimationArray.RemoveAt(_NowSelectFrame);_NowSelectFrame = -1;}}
我们将cube调节成这个样子,然后点击apply应用关键帧
第四步:
选中第三个关键帧,再调到自己满意的形态,并再点击apply应用
第五步:
选中第四个关键帧,这里我们要让他有个缓冲的效果,也就是说跟第三帧的差距小一点
然后我们的第四帧就调成了这个怂样~
第六步:
第五帧我们就要让他发射出去(前几帧是收缩,蓄势,然后第五帧猛地弹出~~有没有一种发射炮弹的感觉~~),当然如果你想复制某一帧的话,只需选中这一帧,点击添加关键帧,最后面就会多出来与此帧相同的一帧,然后在此基础上调节下一帧更方便
第七步:
之后就是给他K几个反弹回来的缓冲关键帧,注意这里选中任意一帧场景中的cube就会变化到那一帧的形态(这种方式是仿Animator的),随意修改之后点击应用可以保存,不点击应用默认改动无效,所以修改之后,如果觉得满意,一定要点击apply应用,否则待你切换到其他帧时,这一帧改动的数据就将丢失
/// <summary>/// 选定指定帧/// </summary>public void SelectFrame(int frameIndex){//如果当前动画帧数据存在,则选定当前动画帧,所有顶点应用当前动画帧数据if (frameIndex >= 0 && frameIndex < _VerticesAnimationArray.Count){_NowSelectFrame = frameIndex;for (int i = 0; i < _Vertices.Length; i++){_Vertices[i].transform.position = _VerticesAnimationArray[frameIndex][i];}}}
第八步:
完成之后点击预览按钮就可以马上在Scene界面看到cube的动画效果,这里没截图,后面用动画播放器播放的时候再截图
因为脚本就算添加了编辑器执行的标识,它的update函数依然不会逐帧执行,而是在场景物体发生变化的时候才执行,所以这里的动画预览函数不能放在update里,那么只有将之加入到Unity编辑器逐帧刷新周期了
/// <summary>/// 预览动画/// </summary>public void PlayAnimation(){//没有动画可以预览if (_VerticesAnimationArray.Count <= 0){return;}//预览从第一帧开始(顶点动画数组下标0)_AnimationIndex = 0;//重置记录动画播放上一序列的变量_AnimationLastIndex = -1;//重建新的动画片段_AnimationFragment = new Vector3[_Vertices.Length];//重置动画播放控制器_AnimationPlayControl = 0;//动画进入到第一帧for (int i = 0; i < _Vertices.Length; i++){_Vertices[i].transform.position = _VerticesAnimationArray[0][i];}_IsPlay = true;//将刷新动画函数注册到Unity编辑器帧执行模块EditorApplication.update += PlayingAnimation;}
动画刷新函数采用将每个关键帧切分为动画片段的方式,将片段循环累加给cube的网格顶点
/// <summary>/// 动画预览中/// </summary>void PlayingAnimation(){if (_IsPlay){//动画播放至最后一帧,动画播放完毕if (_AnimationIndex + 1 >= _VerticesAnimationArray.Count){//动画播放完毕_IsPlay = false;//清除刷新动画函数的注册EditorApplication.update -= PlayingAnimation;//动画回归到第一帧for (int i = 0; i < _Vertices.Length; i++){_Vertices[i].transform.position = _VerticesAnimationArray[0][i];}return;}//当前动画播放序列不等于上一帧序列,则进入下一帧if (_AnimationIndex != _AnimationLastIndex){_AnimationLastIndex = _AnimationIndex;//分割动画片段for (int i = 0; i < _AnimationFragment.Length; i++){_AnimationFragment[i] = (_VerticesAnimationArray[_AnimationIndex + 1][i] - _VerticesAnimationArray[_AnimationIndex][i])/ _AnimationPlaySpeed;}}//动画进行中for (int i = 0; i < _Vertices.Length; i++){_Vertices[i].transform.position += _AnimationFragment[i];}//动画控制器计数_AnimationPlayControl += 1;//动画控制器记录的一个动画帧播放完毕if (_AnimationPlayControl >= _AnimationPlaySpeed){_AnimationPlayControl = 0;_AnimationIndex += 1;}RefishMesh();}}
第九步:
这里是重点了,记得点击导出动画,如果你直接点击编辑完成或是突然有了什么好想法跑去VS里随意改了下脚本导致Unity编辑器重新编译的话,很遗憾你的动画数据都会丢失,记得导出完毕了之后再点击编辑完成
使用scriptableobject序列化动画数据至asset文件中,这里的坑是真坑,路径必须还得是Asset开头,后缀必须还得是asset,刚开始坑了我不少无辜的时间
/// <summary>/// 导出动画/// </summary>public void ExportAnimation(){//动画帧数小于等于1不允许导出if (_VerticesAnimationArray.Count <= 1)return;//创建动画数据文件MeshAnimationAsset meshAnimationAsset = ScriptableObject.CreateInstance<MeshAnimationAsset>();//记录动画顶点数meshAnimationAsset._VertexNumber = _RecordAllVerticesList.Count;//记录动画帧数meshAnimationAsset._FrameNumber = _VerticesAnimationArray.Count;//记录动画帧数据meshAnimationAsset._VerticesAnimationArray = new Vector3[_VerticesAnimationArray.Count * _RecordAllVerticesList.Count];for (int n = 0; n < _VerticesAnimationArray.Count; n++){for (int i = 0; i < _VerticesAnimationArray[n].Length; i++){for (int j = 0; j < _AllVerticesGroupList[i].Count; j++){int number = n * _RecordAllVerticesList.Count + _AllVerticesGroupList[i][j];EditorUtility.DisplayProgressBar("导出动画", "正在导出顶点数据(" + number + "/" + meshAnimationAsset._VerticesAnimationArray.Length + ")......", 1.0f / meshAnimationAsset._VerticesAnimationArray.Length * number);meshAnimationAsset._VerticesAnimationArray[number] = transform.worldToLocalMatrix.MultiplyPoint3x4(_VerticesAnimationArray[n][i]);}}}//创建本地文件string path = "Assets/" + GetComponent<MeshFilter>().sharedMesh.name + "AnimationData.asset";AssetDatabase.CreateAsset(meshAnimationAsset, path);EditorUtility.ClearProgressBar();}
如下就是我们导出来的动画数据,可以看到里面包含了10个关键帧,适用于一切有24个网格顶点的模型(网格顶点是可操控顶点的3倍),当然他的原主是cube
第十步:
然后,为cube添加变形动画播放器组件(MeshAnimationPlayer)并将我们的CubeAnimationData拖到其MeshAnimationAsset属性上,每一个MeshAnimationPlayer对应一个AnimationData文件,暂不支持代码中动态变更
MeshAnimationAsset:动画播放器的目标asset文件,顶点数量需与当前挂载物体一致
AnimationPlaySpeed:动画播放速度,注意,这里是值越小播放越快
另外两个参数是开启循环播放和启动时即播放,我们勾选启动播放,然后运行程序,下面是动态效果图
其他效果:
一个看起来有点丑又有点僵硬的机甲变形(用最新的骨架调节方式,虽然这样还是显得一团糟)
原形:
编辑状态:
变形动画:
MeshAnimationPlayer的播放有外部可控开关
/// <summary>/// 播放动画/// </summary>public void Play(){//从第一帧开始播放(顶点动画数组下标0)_AnimationIndex = 0;//重置记录动画播放上一序列的变量_AnimationLastIndex = -1;//重置动画播放控制器_AnimationPlayControl = 0;//动画跳转到第一帧SelectFrame(_AnimationIndex);_IsPlaying = true;}/// <summary>/// 停止播放/// </summary>public void Stop(){_IsPlaying = false;//动画回归到第一帧SelectFrame(0);}
以及要获取当前动画是否播放中,可以直接读取_IsPlaying属性。
DLL版插件链接:http://download.csdn.net/detail/qq992817263/9659011
-----by MeshEditor
Unity插件 - MeshEditor(五) 网格顶点动画(变形动画)相关推荐
- html文字变成汉堡插件,一组超酷汉堡包图标变形动画特效
Hamburgers是一款效果超酷的汉堡包图标变形动画特效CSS3动画库.这组汉堡包图标动画包括18种不同的汉堡包变形动画效果,你还可以通过Sass文件来自定义你自己的汉堡包图标变形动画. 安装 你可 ...
- css3新增动画属性(过度动画 变形动画 关键帧动画)
目录 过度动画transition 多属性值过渡 2d变形transform 平移 应用:实现居中(不要求知道盒子的宽高) 缩放 旋转 倾斜 修改变形中心的属性 变形属性的复合写法 3D变形动画 3d ...
- Unity插件 - MeshEditor(三) 面片破碎网格破碎
网上的unity破碎插件很多,不过想着可以以自己的方式实现也不失为一种乐趣,虽然整体的表现性上显得有些差,但也并不会影响最终的效果,接下来我大致讲解一下破碎一个物体的流程,因为用到了协程计算碎片的原因 ...
- Unity插件 - MeshEditor(十) 模型风力拉扯特效
更新日期:2020年4月23日. Github源码:[点我获取源码] 先上几张效果图: (导演:我们需要一个刮风的效果,道具组,上大风扇) (导演:咔!!!行了,道具组你们明天不用来上班了) (大风 ...
- 前端HTML5CSS动画变形动画之过渡
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...
- Unity - MorphAnimation 超强变形动画编辑器(一) 蒙皮与变形
索引 前言 MorphAnimation的使用(一) 创建变形网格 MorphAnimation的使用(二) 基本设置 MorphAnimation的使用(三) 编辑骨骼 MorphAnimation ...
- 日落20181218001 - Unity插件应用之ShaderForge制作顶点动画
环境 系统:Windows 10 引擎:Unity 2017.2.1f1 工具:Shader Forge 1.38 目的 使用Shader Forge制作顶点动画的实例. (1)场景布局如下. (1- ...
- Unity插件:Unity使用spine动画
一.spine动画介绍 动画能给游戏带来生机和灵气.我们相信创作一段美妙的动画,不仅需要强大的软件工具,更需要一套牛 B 的工作流程.Spine 专注于此,为您创建惊艳的骨骼动画,并将其整合到游戏当中 ...
- unity3d android 路径动画制作,Lesson11.Unity路径动画、路径变形动画实现方式
鲸鱼的絮絮叨叨 Lesson01.unity简介和菜单栏介绍 Lesson02.unity粒子系统_1 Lesson02.unity粒子系统_2 Lesson03.3dmax粒子系统_1 Lesson ...
- Unity插件之NGUI学习(4)—— 创建UI2DSprite动画
创建一个新的Scene.并按 Unity插件之NGUI学习(2)创建UI Root,并在UI Root的Camera下创建一个Panel. 然后在选中Panel,在菜单中选择NGUI->Crea ...
最新文章
- 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus
- Redis 禁止使用耗时命令和时间复杂度为O(n)的命令
- IntelliJ IDEA 添加对 Extjs6 支持
- python合并两个文本文件内容_Python将多个txt文本合并为一个文本的代码
- 【计算机网络】物理层 : 编码 ( 数字数据 编码 数字信号 | 非归零编码 | 归零编码 | 反向不归零编码 | 曼彻斯特编码 | 差分曼彻斯特编码 | 4B/5B 编码 )
- fastboot使用
- Android Studio控件属性大全
- 曼哈顿距离最小生成树(树状数组)
- WebRTC 非常适用于智能家庭安防摄像头
- 深入学术研究,物理学家用VR演示弦理论猜想
- ei会议论文录用但不参加会议_同一个EI会议录用的文章一定全部都进EI吗?
- Java调用有道翻译API包括APPID/密钥地址注册
- 国瀚实业|怎么才能做好互联网投资理财
- ElasticSearch 2.4.X实现中文拼音排序
- 大数据掀人类文明革命 探索更多未知
- 类和对象:类与对象定义
- 使用wiki百科和gensim训练中文词向量
- Leetcode1407. 排名靠前的旅行者
- 忘记网站登录密码不要慌,一招拯救你
- 解决Windows 7播放网页视频没有声音的问题
热门文章
- css svg做动图,如何制作svg动态图
- 华为的人力资源管理揭秘
- Windows PE (老毛桃) 介绍功能介绍
- 三维分布图 matlab,怎样用matlab画三维三点分布图
- 两步完成druid数据库连接池的密文配置
- 2D姿势估计论文合集
- h30-t10 android phone,荣耀3C移动2G版(H30-T10)官方完整版ROM全合集!!!
- error: system libzip must be upgraded to version #62= 0.11【问题解决】php7编译zip报错
- linux篇—Nginx反向代理负载均衡
- webSphere介绍