(来自:有爪的小羔羊阿赵)
作为Unity4.0的主要更新功能,Mecanim动画被寄予了很多的期望。系统有先进的地方,也有不足的地方。这些我们留到最后再来总结。
阿赵粗略的学习了一下,写下以下的教程。这篇教程简单的说明了Mecanim系统的用法和控制方式,里面用到的资源,是从AssetStore里面下载的,如果有兴趣的朋友可以去免费下载。
学习目标:
我预先准备了几个没有带动画的3d模型,fbx格式,和一些导出好的动画文件。
我们要做的事情,就是使用新的动画系统,把这些动画做出状态机,赋予给这些没有动画的模型。这样得到的好处就是,我们可以把模型制作和动画制作分开了,只要我们的模型分别蒙皮了,就可以比较随意的共享使用相同的动画。如果状态机控制得当的话,人物的动画控制也会比较容易。
准备工作:
准备几个这种已经蒙好皮,但没有动作的FBX模型:
和几个现成的动画文件。这些文件可以是用Maya直接导出,或者用3Dmax直接导出了带动画的Fbx文件,然后在Unity的导入器里面切割。
这个切割的过程和之前的动画系统一样:
开始制作:
从Unity4.0开始,模型导入器的选项变化比较大,他分为了Model、Rig和Animations三个标签。
Model标签页和以前的基础设置差不多,还是网格、法线和索引、材质的设置:
Animations标签栏里面的内容和上面的切割动画时是一样的,不过对于没有带动画的模型,我们可以把导入动画的选项取消。
Rig标签栏是重点:
我们想要使用新的Mecanim系统,必须让模型拥有一个设置好的Avatar,所以我们必须把Rig里面的内容选成这样:
Avatar可以是从本身的模型创建,或者从其他Avatar拷贝过来。选择了之后,我们还可以通过图片内红框的按钮来打开Avatar的编辑器。
在项目资源浏览器里面找到该FBX模型,我们可以看到,红框所标记的文件,就是该模型的Avatar了。
在这里也可以打开Avatar的编辑器。
下面我们就开始制作Avatar:
打开Avatar的时候,会提示你保存现有的场景。因为Avatar是会打开新的独立场景来编辑的。
这个是Avatar的选项。分为了身体(Body)、头部(Head)、左手(Left Hand)、右手(Right Hand)四个部分。每个部分分别有几个骨骼,我们需要做的事情,就是把我们准备好的人物身上的骨骼指定到这些部位。
这里估计也不需要过多的解释了,当你点击一个选项的时候,在上面的人体图会标记处当前选择的部位,比较直观。
如果觉得逐个骨骼指定很麻烦,我们也可以从下面的Mapping里面选择自动适配(Automap),这样Unity会帮你识别人物结构并指定骨骼。我试了一下,这个自动适配的准确率还是很高的。不过一些细节部位,比如手指和眼之类,还是要自己指定。除了自动适配,我们还可以保存和读取设置。
指定好了,我们想保存,不过发现提示有错误,角色不是在T的姿势。
在Pose里面选择Enforce T-Pose
这样角色就会变成了T型的姿势。现在我们可以保存这个Avatar了。
做好的Avatar还可以在Muscles栏里面测试蒙皮的效果,在里面可以针对不同的部位做一些动作,比如弯曲身体,扭腰等,看看蒙皮的效果十分正常。
接下来我们要制作动画控制器。
需要的材料就是我们刚才准备了的几个动画。
这是Mecanim动画系统的Animator组件,你只需要把刚才的FBX模型拖到场景,就能看到:
拖到场景中后,发现模型不会播放动画,这是因为红框标记的地方缺少了动画控制器。接下来我们就来制作自己的动画控制器。
在项目资源管理器里面右键,创建Animator Controller。
一个新的Animator Controller被创建出来了。
接下来我们需要打开Animator编辑面板:
这就是默认的Animator面板:
选择刚才我们新建的Animator Controller,然后把动画拖入Animator面板:
现在我们的控制器里面有4段动画了。如果现在把这个控制器拖给人物,人物就会播放默认的动作。现在的默认动作是death,我们想把默认动作指定成idle2。
右键单击idle2,然后选择Set As Default:
这时候,idle2的颜色已经变了,它变成了默认的动作:
接下来我们分析一下,这个上面写着idle2的方块究竟代表了什么意思吧:
在属性栏里面,我们可以看到,这个方块代表了一个动作。而这个方块可以设置播放的速度。可以指定方块里面代表的动画片段。可以指定是否启用脚部IK。就算刚才我们拖了的这个方块是idle2,我们也可以手动在这里选择另外的动画片段。
除了代表现有的动画片段,这个方块还可以代表某几个动画的融合。
这里我们需要建立一个新的混合树:
右键点击idle2,然后选择Create newBlendTree in State
现在再看属性,我们看到在Motion里面不再是现有的动画片段,而是Blend Tree了。
Unity3D 4.0新功能:Mecanim动画系统基础教程 - 阿赵 - 有爪的小羔羊阿赵
这时候双击idle2方块,会进入下一层级
里面有一个Blend Tree。
在属性栏里面点击加号,可以添加多段动画给混合树。
比如我们这里新建两个动画片段,然后把idle0和idle2拖进去。
再看混合树的图示,会发现出现了两个节点。我们可以通过调节Blend的数字来控制动画混合的影响权重。
到此为止,动画方块代表的内容我们已经了解清楚了。
接下来需要做的,就是把这些动画连接起来,比如从idle2到death的动画,我们过可以建立一个单向的指向转换。这代表着,当达到某个条件的时候,角色会从做idle2动画转变成death动画。
右击idle2,然后选择Make Transition,可以拉出一个箭头线段:
当然反过来,就可以创建一条从death到idle2的箭头线段了。
刚才说了,这个箭头线段代表了在某个条件达到后,动画的转换。那么这个条件在哪里设置呢?
我们可以选择一条箭头线段,然后
看到属性栏里面,有这条线段的设置。包括了上一段动画、下一段动画之间的过渡情况,还有过渡时的条件(Conditions)。这个条件是可以多个的,可以按加号添加。
现在我们点击第一个默认的条件(Exit Time),我们发现没有其他的选择,也就是说,现在动画之间只能通过时间作为条件来过渡,当上一个动画播放到一定时间后,就会转到下一个动画。
那么怎样设置其他的条件呢?
在animator面板的左下角,我们找到参数选项Parameters,点击加号添加。
比如我们现在创建两个布尔的参数
创建完之后,我们需要输入参数的名称。这里我们想使用布尔来控制是否可以转换动画,所以我们把这两个参数起名为Idle2ToDeath和DeathToIdle2。
现在回到刚才选择条件的地方,我们发现,
刚才设置的两个参数已经可以选择了,也就代表了,我把idle2到death的线的条件设置成Idle2ToDeath,那么只有当Idle2ToDeath为true的时候,这个动画的转换才会成立。
为了试验,我们把idle2到death的线的条件还是保持默认的Exit Time,不过把death到idle2的线的条件变成了DeathToIdle2。
现在我们可以把这个新作的Animator Controller拖到人物身上:
现在播放,我们可以看到人物先显示了idle2的动画,然后会接着播放death的动画,最后人物倒在地上不动了。这是因为,idle2到death的条件是时间,所以过一定的时候后,就会接着播放death,但到了death后,由于回到idle2的条件是DeathToIdle2 = true,但默认是false的,所以人物不能回到idle2的状态。
为了使人物在我们希望的时候回到idle2状态,我们需要编写一个脚本:
using UnityEngine; using System.Collections; public class FirstMecanimScript : MonoBehaviour { public Animator animator; void OnGUI() { if(GUILayout.Button("StandUp") && animator) { animator.SetBool("DeathToIdle2", true); } } }当按下按钮时,使用SetBool的方法把指定的DeathToIdle2设定为true。
using UnityEngine; using System.Collections; public class FirstMecanimScript : MonoBehaviour { public Animator animator; public string[] cmds; public string currentState = string.Empty; void Update() { CheckState(); } void OnGUI() { for( int i=0; i<cmds.Length; i++) { if(GUILayout.Button(cmds[i])) { currentState = cmds[i]; } } } private void CheckState() { if(!string.IsNullOrEmpty(currentState)) { Debug.Log(currentState); } AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); if(!stateInfo.IsName("Base Layer.idle2")) { animator.SetBool("Idle2ToDeath", false); } else { animator.SetBool("DeathToIdle2", false); } if(!string.IsNullOrEmpty(currentState)) { switch(currentState) { case "death": animator.SetBool("Idle2ToDeath", true); break; case "idle2": animator.SetBool("DeathToIdle2", true); break; } currentState = string.Empty; } } }
除了death到idle2是需要用布尔条件,其他的单向线条都是使用时间作为条件。这时候,我们播放,会看到人物先做idle2的动作,然后做idle1动作,再做idle0动作,最后做death动作,倒下后就不起来了,按按钮后,人物起来,再重复上面的动作,最后又倒下。
这里给我们的提示是,我们可以通过这样的单向线条和条件,把一些单个的动作连接成一套完整的动作,最常用的就是过场动画了,或者是动作游戏的连招。最后,我们把上面的例子做完整吧。
最后的脚本,修改一下CheckState方法:
using UnityEngine; using System.Collections; using System.Collections.Generic; public class FirstMecanimScript : MonoBehaviour { public Animator animator; public List<string> cmds = new List<string>(){"idle0", "idle1", "death"}; public string currentState = string.Empty; void Update() { CheckState(); } void OnGUI() { for( int i=0; i<cmds.Count; i++) { if(GUI.Button(new Rect(10,40*(i+1),60,32), cmds[i])) { currentState = cmds[i]; } } } private void CheckState() { if(!string.IsNullOrEmpty(currentState)) { Debug.Log(currentState); } if(!string.IsNullOrEmpty(currentState)) { switch(currentState) { case "death": animator.SetBool("Idle2ToDeath", true); break; case "idle0": animator.SetBool("Idle2ToIdle0", true); break; case "idle1": animator.SetBool("Idle2ToIdle1", true); break; } currentState = string.Empty; } } }好了,这样,我们的人物已经可以通过脚本控制他在各个动作状态之间转换了。