尽管Unity中的动画工具已经比较强大了,但对于非常复杂的或很长的动画,通常是由外部DCC创建。特别是对于角色动画来说,需要在动画过程中进行复杂的控制。因此我们通常需要将外部制作的动画导入到Unity中。
动画能被共享吗
对于复杂的动画,制作过程会非常耗时。动画师常常要决定在一个项目中如何最佳地分配时间和精力。对于背景中的角色或不需要单独制作的动画,可以选择使用预先构建好的动画。并非所有角色类型都能轻易地使用为另一个rig所构建的动画(关于rig,可以先简单理解为骨骼)。但在Unity中,只要是遵循基础的humanoid形状(一个头,两条胳膊,两条腿儿)的角色,都能使用人形动画系统(Humanoid Animation System)。在这个系统中,Unity会根据rig里的关节信息,将现有的动画从一个人形角色转换到另一个角色上。这就是说即便外观看起来非常不同的角色也能共享同样的动画集。
对于其他类型的动画,其实也能够实现复用(前提是动画信息文件里的关键信息能对上)。关于动画复用的较为详细的描述,可以参考B站一位大佬的视频:
配置动画类型
我们想要导入Unity的动画,可能有多个动画文件表示不同的动画,也可能只在一个动画文件里包含了多有动作的动画。对于一个动画文件包含多个动作动画的情况,导入Unity后,我们可以在import setttings里进行分割。
接下来我们以人形动画为例来看看,动画类型的配置过程。
1. 在Animations目录中,选择我们要导入的动画,案例中是一个Dance_x3的动画(Unity官方Creative Core -> Animation部分有相关资源包,如果要使用请自行去下载)。
2. 在Inspector中,选择Rig标签页,这个标签页包含了rig相关的导入选项。
默认情况下,即便是和Humanoid Animation System兼容的rigs,其动画类型(Animation Type)也是Generic。这种动画类型会避免动画共享其他rigs的信息。
3. 我们将Animation Type选择为Humanoid,然后点击Apply。
这样动画就被配置为了Humanoid类型了。
配置第一个动画片段
接下来我们来看看动画导入设置中的Animation标签页。
1. 在动画的Inspector中,选择Animation标签页。
2. 在Inspector的底部,点击Play按钮预览动画。
我们可以看到,这个导入的动画里,有三种不同的跳舞的动作序列。我们要将这三个动作分别做成三个动画片段。在Animation标签页的上半部分,有一个Clips,这个Clips就是我们定义独立动画片段的地方了。
3. 在Clips部分,点击“+”按钮两次,复制一下当前的动画片段。
4. 在Clips下选择名为Dance_X3的第一个片段,将其重命名为Dance_01。
这个Dance_01作为第一个舞蹈动画序列,我们后面会对它的起始和结束帧进行调整。
5. 我们在动画预览窗口中,我们通过拖动鼠标来确定一下第一个跳舞动画的开始帧和结束帧。
在我们重命名动画片段处正下方,有一条时间轴,以及一个Start和End,分别表示此动画片段是从原始完整动画片段中起始帧和结束帧的帧序号。由于这是第一个跳舞片段,因此起始帧保持为1,结束帧我们需要根据实际情况填写。
6. 在End中,填入150。
7. 预览动画,确保动画循环播放时看起来无缝衔接,如果有需要就调整End的值。
注意:在预览窗口中,动画是循环播放的,但实际上这个动画当前被设置为了只播放一次。
8. 启用Loop Time,让动画能够循环播放。
我们会观察到在预览窗口中,角色脚下的地面看起来像是在移动。这是因为这个动画序列关联了root motion。如果打开root motion,则角色在动画过程中看起来就像是在地面上滑动着。当前案例中,我们将其简单地关闭掉就好了。关于root motion本身,B站一位大佬(前面提到的那位)有非常详细地说明,请到B站去看看大佬关于root motion讲解的视频。
9. 在Root Transform Rotiaon, Root Transform Position(Y)和Root Transform Position(XZ)中,启用Bake inot Pose。
现在预览动画时,地面看起来不会再发生变化了。
配置剩下的两个动画片段
1. 选择Clips列表里的第二个动画片段(当前名字为Take001),将其重命名为Dance_02。
2. 设置开始帧为151,结束帧为260。
3. 启用Loop Time。
4. 在Root Transform Rotiaon, Root Transform Position(Y)和Root Transform Position(XZ)中,启用Bake inot Pose。
5. 选择Clips列表中的最后一个片段,将其重命名为Dance_03。
6. 将其开始帧设为261,结束帧设为350。
7. 启用Loop Time。
8. 在Root Transform Rotiaon, Root Transform Position(Y)和Root Transform Position(XZ)中,启用Bake inot Pose。
做完这些操作后,在Inspector中滚动鼠标找到最下方的Apply,点击它保存所有修改。
添加新增的动画片段到动画控制器中
我们可以将新增的动画片段加入到现有的Animator Controller中。案例中所使用的Animation Controller名字为Shared_Controller。
1. 在Animations目录下找到Shared_Controller,双击在Animator中打开这个文件。
2. 我们将Animator放置到场景视图下方,这样方便同时观察场景和Animator。
3. 定位到Dance_X3所在位置,将其点开,查看所有新增的动画片段。
4. 将这三个新增动画片段拖动到Animator编辑器窗口中
为场景中的要跳舞的每个角色,都挂上一个DanceParty的脚本,这个脚本功能很简单,在按不同按键时(Q,W,E),会对应去触发Dance_01,Dance_02和Dance_03三个Trigger类型的参数。脚本内容如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DanceParty : MonoBehaviour
{
private Animator anim;
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Q))
{
anim.SetTrigger("Dance_01");
}
if (Input.GetKeyDown(KeyCode.W))
{
anim.SetTrigger("Dance_02");
}
if (Input.GetKeyDown(KeyCode.E))
{
anim.SetTrigger("Dance_03");
}
}
}
5. 在Animator中的Parameters页面中,点击“+”,添加三个Trigger参数,名字和脚本里的Trigger参数名一样。
当用户按下Q,W或E时,角色应该停止他们正在做的动作并开始跳舞。由于这对于任何时间点来说都必须要发生的事情,因此我们使用Any State节点。Any State节点可以打断状态机里的任何转换(transition)过程,并且调用和它关联的动画。
8. 在Animatior中,右键点击Any State节点,选择Make Transition,将它和Dance_01节点相连。
9. 选择这个新建的转换(transition),在其Inspector中点击“+”,在conditions那里,选择Dance_01参数。
10. 右键点击Dance_01节点,选择Make Transition,并且将它和Exit节点相连。
11. 用相同的方法设置Dance_02和Dance_03。
12. 点击Play,按Q,W,E键看看效果。