网格顶点动画(变形动画)是针对于物体的形状可以随意变换并记录为关键帧的动画,虽然模型的顶点数据还是应该交给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(五) 网格顶点动画(变形动画)相关推荐

  1. html文字变成汉堡插件,一组超酷汉堡包图标变形动画特效

    Hamburgers是一款效果超酷的汉堡包图标变形动画特效CSS3动画库.这组汉堡包图标动画包括18种不同的汉堡包变形动画效果,你还可以通过Sass文件来自定义你自己的汉堡包图标变形动画. 安装 你可 ...

  2. css3新增动画属性(过度动画 变形动画 关键帧动画)

    目录 过度动画transition 多属性值过渡 2d变形transform 平移 应用:实现居中(不要求知道盒子的宽高) 缩放 旋转 倾斜 修改变形中心的属性 变形属性的复合写法 3D变形动画 3d ...

  3. Unity插件 - MeshEditor(三) 面片破碎网格破碎

    网上的unity破碎插件很多,不过想着可以以自己的方式实现也不失为一种乐趣,虽然整体的表现性上显得有些差,但也并不会影响最终的效果,接下来我大致讲解一下破碎一个物体的流程,因为用到了协程计算碎片的原因 ...

  4. Unity插件 - MeshEditor(十) 模型风力拉扯特效

    更新日期:2020年4月23日.  Github源码:[点我获取源码] 先上几张效果图: (导演:我们需要一个刮风的效果,道具组,上大风扇) (导演:咔!!!行了,道具组你们明天不用来上班了) (大风 ...

  5. 前端HTML5CSS动画变形动画之过渡

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  6. Unity - MorphAnimation 超强变形动画编辑器(一) 蒙皮与变形

    索引 前言 MorphAnimation的使用(一) 创建变形网格 MorphAnimation的使用(二) 基本设置 MorphAnimation的使用(三) 编辑骨骼 MorphAnimation ...

  7. 日落20181218001 - Unity插件应用之ShaderForge制作顶点动画

    环境 系统:Windows 10 引擎:Unity 2017.2.1f1 工具:Shader Forge 1.38 目的 使用Shader Forge制作顶点动画的实例. (1)场景布局如下. (1- ...

  8. Unity插件:Unity使用spine动画

    一.spine动画介绍 动画能给游戏带来生机和灵气.我们相信创作一段美妙的动画,不仅需要强大的软件工具,更需要一套牛 B 的工作流程.Spine 专注于此,为您创建惊艳的骨骼动画,并将其整合到游戏当中 ...

  9. unity3d android 路径动画制作,Lesson11.Unity路径动画、路径变形动画实现方式

    鲸鱼的絮絮叨叨 Lesson01.unity简介和菜单栏介绍 Lesson02.unity粒子系统_1 Lesson02.unity粒子系统_2 Lesson03.3dmax粒子系统_1 Lesson ...

  10. Unity插件之NGUI学习(4)—— 创建UI2DSprite动画

    创建一个新的Scene.并按 Unity插件之NGUI学习(2)创建UI Root,并在UI Root的Camera下创建一个Panel. 然后在选中Panel,在菜单中选择NGUI->Crea ...

最新文章

  1. 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus
  2. Redis 禁止使用耗时命令和时间复杂度为O(n)的命令
  3. IntelliJ IDEA 添加对 Extjs6 支持
  4. python合并两个文本文件内容_Python将多个txt文本合并为一个文本的代码
  5. 【计算机网络】物理层 : 编码 ( 数字数据 编码 数字信号 | 非归零编码 | 归零编码 | 反向不归零编码 | 曼彻斯特编码 | 差分曼彻斯特编码 | 4B/5B 编码 )
  6. fastboot使用
  7. Android Studio控件属性大全
  8. 曼哈顿距离最小生成树(树状数组)
  9. WebRTC 非常适用于智能家庭安防摄像头
  10. 深入学术研究,物理学家用VR演示弦理论猜想
  11. ei会议论文录用但不参加会议_同一个EI会议录用的文章一定全部都进EI吗?
  12. Java调用有道翻译API包括APPID/密钥地址注册
  13. 国瀚实业|怎么才能做好互联网投资理财
  14. ElasticSearch 2.4.X实现中文拼音排序
  15. 大数据掀人类文明革命 探索更多未知
  16. 类和对象:类与对象定义
  17. 使用wiki百科和gensim训练中文词向量
  18. Leetcode1407. 排名靠前的旅行者
  19. 忘记网站登录密码不要慌,一招拯救你
  20. 解决Windows 7播放网页视频没有声音的问题

热门文章

  1. css svg做动图,如何制作svg动态图
  2. 华为的人力资源管理揭秘
  3. Windows PE (老毛桃) 介绍功能介绍
  4. 三维分布图 matlab,怎样用matlab画三维三点分布图
  5. 两步完成druid数据库连接池的密文配置
  6. 2D姿势估计论文合集
  7. h30-t10 android phone,荣耀3C移动2G版(H30-T10)官方完整版ROM全合集!!!
  8. error: system libzip must be upgraded to version #62= 0.11【问题解决】php7编译zip报错
  9. linux篇—Nginx反向代理负载均衡
  10. webSphere介绍