版本: 2022.3
语言: 英语
动画
用户界面(UI)

动画脚本(旧版)

Unity的动画系统允许您创建美丽的动画皮肤角色。动画系统支持动画混合、混合、加法动画、行走周期时间同步,动画层动画层包含一个动画状态机,该状态机控制模型或其部分的动画。例如,如果您有一个用于走路或跳跃的全身层,以及一个用于投掷物体或射击等上身运动的较高层,这就是一个例子。较高层对其控制的身体部分具有优先权。 更多信息
请在 术语表 中查看
,控制动画播放的各个方面(时间、速度、混合权重),网格Unity的主要图形原语。网格构成了您3D世界的大部分。Unity支持三角化或四边化多边形网格。Nurbs、Nurms、Subdiv曲面必须转换为多边形。 更多信息
请在 术语表 中查看
蒙皮将骨骼关节绑定到角色的网格或“皮肤”顶点的过程。由外部工具执行,例如Blender或Autodesk Maya。 更多信息
请在 术语表 中查看
每个顶点使用1、2或4个骨骼,并支持基于物理的娃娃和过程动画。为了获得最佳结果,建议您在优化角色建模页面阅读最佳实践和技术,以在Unity中创建具有最佳性能的骨架角色。

创建动画角色涉及两个方面;移动角色通过世界并在相应地进行动画。如果您想了解更多关于角色移动的内容,请查看角色控制器页面。本页面重点介绍动画。实际给人物的动画是通过Unity的脚本接口完成的。

您可以下载示例演示,显示预先设置好的动画角色。在本页面上学习基础知识之后,您还可以查看动画脚本接口

动画混合

在今天的游戏中,动画混合是一个必不可少的特性,以确保角色拥有平滑的动画。动画师创建单独的动画,例如,行走周期、跑步周期、闲置动画或射击动画。在游戏的任何时刻,您都需要能够从闲置动画切换到行走周期,反之亦然。当然,您希望这种转换是平滑的,避免运动中的突然跳跃。

这就是动画混合发挥作用的地方。在Unity中,您可以为同一个角色播放任意数量的动画。所有动画都混合或相加生成最终动画。

我们的第一步是使角色在闲置和行走动画之间进行平滑混合。为了使脚本者的工作更简单,我们首先将动画的循环模式设置为循环。然后我们关闭自动播放,以确保我们的脚本是唯一的播放动画者。

我们为角色动画准备的第一段脚本相当简单;我们只需要一种方法来检测角色移动的速度,然后就在步行和空闲动画之间淡入淡出。对于这次简单的测试,我们将使用标准输入轴:

function Update () {
   if (Input.GetAxis("Vertical") > 0.2)
       animation.CrossFade ("walk");
   else
      animation.CrossFade ("idle");
}

要在您的项目中使用此脚本:

  1. 使用 资源 > 创建 > JavaScript 创建一个 JavaScript 文件。
  2. 将代码复制并粘贴到其中
  3. 将脚本拖放到拥有动画的角色上(它需要附加到具有动画的 GameObjectUnity 场景中的基本对象,可以代表角色、道具、场景、相机、路点等等。GameObject的功能由附加到其上的组件定义。 更多信息
    术语表中查看
    上)

当您按下播放按钮时,当您按下上箭头键时,角色将开始原地行走,当您释放它时,角色将回到空闲姿势。

动画图层

图层是一个非常有用的概念,使您可以分组动画并优先处理权重。

Unity 的动画系统可以在任意多 动画剪辑可以用于动画角色或简单动画的动画数据。它是一个简单的“单元”运动片段,如(特定实例)“Idle”,“Walk”或“Run”。 更多信息
术语表中查看
之间混合。您可以手动分配混合权重,也可以简单地使用 animation.CrossFade(),这将自动调整权重。

在应用前,混合权重始终被归一化

假设您有一个步行循环和一个跑步循环,它们的权重都是 1(100%)。当 Unity 生成最终动画时,它将归一化权重,这意味着步行循环将贡献 50% 的动画,跑步循环也将贡献 50%。

然而,当有两个动画同时播放时,通常希望优先考虑哪个动画接收更多的权重。虽然可以手动确保权重总和为 100%,但使用图层来达到这一目的会更简单。

分层实例

例如,您可能有一个射击动画、一个空闲状态和一个步行循环。基于玩家的速度,步行和空闲动画将被混合,但是在玩家射击时,您只想显示射击动画。因此,射击动画实际上具有更高的优先级。

要实现这一点,最简单的方法是在射击时继续播放步行和空闲动画。为了做到这一点,我们需要确保射击动画位于比空闲和步行动画更高的图层上,这意味着射击动画将首先接收混合权重。只有在射击动画没有使用所有 100% 的混合权重的情况下,空闲和步行动画才会接收权重。所以,当在进入 CrossFading 射击动画时,其权重将从零开始,在短时间内变为 100%。开始时,步行和空闲图层仍然会接收混合权重,但当射击动画完全淡入时,它们将不再接收任何权重。这正是我们需要的!

function Start () {
   // Set all animations to loop
   animation.wrapMode = WrapMode.Loop;
   // except shooting
   animation["shoot"].wrapMode = WrapMode.Once;

   // Put idle and walk into lower layers (The default layer is always 0)
   // This will do two things
   // - Since shoot and idle/walk are in different layers they will not affect
   // each other's playback when calling CrossFade.
   // - Since shoot is in a higher layer, the animation will replace idle/walk
   // animations when faded in.
   animation["shoot"].layer = 1;

   // Stop animations that are already playing
   //(In case user forgot to disable play automatically)
   animation.Stop();
}

function Update () {
   // Based on the key that is pressed,
   // play the walk animation or the idle animation
   if (Mathf.Abs(Input.GetAxis("Vertical")) > 0.1)
      animation.CrossFade("walk");
   else
      animation.CrossFade("idle");

   // Shoot
   if (Input.GetButtonDown ("Fire1"))
      animation.CrossFade("shoot");
}

默认情况下,animation.Play()animation.CrossFade() 将停止或淡出同一图层中运行的动画。在实际情况下,这正是我们想要的。在我们的射击、空闲、跑步示例中,播放空闲和跑步将不会影响射击动画,反之亦然(如果您喜欢,可以通过 animation.CrossFade 的可选参数来改变这种行为)。

动画混合

动画混合允许您通过让某些动画只应用于身体的一部分来减少您需要为游戏创建的动画数量。这意味着这类动画可以与其他动画以各种组合方式一起使用。

您可以通过在给定的动画状态上调用 AddMixingTransform() 来向动画添加动画混合转换。

混合示例

混合的一个例子可能是一个挥手动画。您可能希望在角色空闲或行走时让手部挥手。如果没有动画混合,您将不得不为空闲和行走状态创建分别的手部挥手动画。但是,如果将肩部转换作为混合转换添加到挥手动画中,则挥手动画将只在肩膀到手的范围内完全控制。由于身体的其余部分不会受到挥手动画的影响,它将继续播放空闲或行走动画。因此,只需要一个动画就可以让手部挥手,同时身体的其余部分使用空闲或行走动画。

/// Adds a mixing transform using a Transform variable
var shoulder : Transform;
animation["wave_hand"].AddMixingTransform(shoulder);

另一个使用路径的例子。

function Start () {
   // Adds a mixing transform using a path instead
   var mixTransform : Transform = transform.Find("root/upper_body/left_shoulder");
   animation["wave_hand"].AddMixingTransform(mixTransform);
}

附加动画

附加动画和动画混合可以帮助您减少创建游戏所需动画的数量,这对于创建人脸动画非常重要。

假设您想创建一个角色在行走和跑步时转向时向两侧倾斜。这会产生四种组合(行走-倾斜左,行走-倾斜右,跑步-倾斜左,跑步-倾斜右),每种组合都需要一个动画。为每种组合创建单独的动画在这样简单的情况下也会导致大量额外的工作,但随着动作的不断增加,组合的数量会急剧增加。幸运的是,附加动画和混合避免了为简单运动的组合制作单独动画的需要。

附加动画示例

附加动画允许您将一个动画的效果叠加在任何可能正在播放的动画之上。在生成附加动画时,Unity将计算动画剪辑的第一帧和当前帧之间的差异。然后,它将这个差异应用于所有其他正在播放的动画。

参考之前的示例,您可以制作向右和向左倾斜的动画,Unity将能够在行走、空闲或跑步周期上叠加这些动画。这可以通过以下代码实现:-

private var leanLeft : AnimationState;
private var leanRight : AnimationState;

function Start () {
   leanLeft = animation["leanLeft"];
   leanRight = animation["leanRight"];

   // Put the leaning animation in a separate layer
   // So that other calls to CrossFade won't affect it.
   leanLeft.layer = 10;
   leanRight.layer = 10;

   // Set the lean animation to be additive
   leanLeft.blendMode = AnimationBlendMode.Additive;
   leanRight.blendMode = AnimationBlendMode.Additive;

   // Set the lean animation ClampForever
   // With ClampForever animations will not stop
   // automatically when reaching the end of the clip
   leanLeft.wrapMode = WrapMode.ClampForever;
   leanRight.wrapMode = WrapMode.ClampForever;

   // Enable the animation and fade it in completely
   // We don't use animation.Play here because we manually adjust the time
   // in the Update function.
   // Instead we just enable the animation and set it to full weight
   leanRight.enabled = true;
   leanLeft.enabled = true;
   leanRight.weight = 1.0;
   leanLeft.weight = 1.0;

   // For testing just play "walk" animation and loop it
   animation["walk"].wrapMode = WrapMode.Loop;
   animation.Play("walk");
}

// Every frame just set the normalized time
// based on how much lean we want to apply
function Update () {
   var lean = Input.GetAxis("Horizontal");
   // normalizedTime is 0 at the first frame and 1 at the last frame in the clip
   leanLeft.normalizedTime = -lean;
   leanRight.normalizedTime = lean;
}

提示:当使用附加动画时,您还必须在每个也用于附加动画的转换上播放一些其他非附加动画,否则动画将叠加到最后一帧的结果上。这绝对不是您想要的结果。

通过过程动画角色

有时您想要以编程方式为角色的骨骼动画。例如,您可能想让角色的头部看向三维空间中的特定点,这最好通过一个跟踪目标点的脚本处理。幸运的是,Unity使得这变得非常简单,因为骨骼只是驱动着骨骼网格的Transform。因此,您可以从脚本中控制角色的骨骼,就像控制GameObject的Transform一样。

需要注意的是,动画系统在Update()函数之后和在LateUpdate()函数之前更新Transform。因此,如果您想进行LookAt()操作,您应该在LateUpdate()中执行,以确保您真正覆盖了动画。

玩偶的创建方式相同。您只需要将 Rigidbody一个组件,允许GameObject受到模拟重力和其他力的作用。 更多信息
术语表中查看
Character Joints一个扩展的球窝关节,允许在每个轴向上限制关节。主要用于玩偶效果。 更多信息
术语表中查看
和胶囊 Collider一个用于处理对象物理碰撞的不可见形状。Collider不必与对象的网格形状完全相同 - 通常一个粗略的近似更有效,并且在游戏中不可区分。 更多信息
术语表中查看
附加到不同的骨骼上。这样就可以物理地动画化您的蒙皮角色。

动画播放和采样

本节解释了Unity中在动画被播放时,引擎是如何进行采样的。

AnimationClips通常以固定帧率创建。例如,您可以在Autodesk® 3ds Max®或Autodesk® Maya®中以60 帧每秒在运行的游戏中连续帧的显示频率。更多信息
术语表中查看
(fps)的帧率创建动画。当将动画导入Unity时,导出器将读取此帧率,因此导入的动画数据也将以60 fps参见第一人称射击,帧每秒。
术语表中查看
进行采样。

然而,游戏通常以可变帧率运行。在一些计算机上,帧率可能高于其他计算机,并且它还可能根据在任何给定时刻摄像机查看视图的复杂度而一秒一秒地变化。基本上这意味着我们无法假设游戏运行的确切帧率。这意味着即使动画是以60 fps创建的,它在不同的帧率下播放,如56.72 fps、83.14 fps或几乎任何其他值。

因此,Unity必须在可变帧率下对动画进行采样,并无法保证其原始设计的帧率。幸运的是,3D计算机图形动画不是由离散帧组成,而是一系列连续的曲线。这些曲线可以在任何时间点进行采样,而不仅仅是与原始动画中的帧对应的时间点。实际上,如果游戏的帧率高于动画的创建帧率,动画在游戏中的显示将比在动画软件中更平滑、更流畅。

对于大多数实际用途,你可以忽略Unity根据可变帧率采样的动画这个事实。然而,如果你有依赖于动画的游戏逻辑,该动画将变换或属性转换为非常具体的配置,那么你需要知道重新采样是在场景场景包含你的游戏环境和方法。将每个单独的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍和装饰,实际上是分步骤设计和构建你的游戏。更多信息
查看词汇表
中进行的。例如,如果你有一个动画在30帧内将对象从0度旋转到180度,你想从你的代码中知道它何时到达一半,你不应该在代码中使用一个条件语句来检查当前旋转是否为90度。因为Unity根据游戏的变量帧率来采样动画,它可能刚好在90度以下采样,而下一帧就在它达到90度之后采样。如果你想通知达到动画中特定点,应使用AnimationEvent

注意,由于可变帧率采样,使用WrapMode.Once播放的动画可能不会在最后一帧的确切时间采样。在一帧的游戏中,动画可能在动画即将结束时被采样,在下一帧中时间可能已经超过了动画长度,因此它被禁用且不再被采样。如果你绝对需要精确采样动画的最后一帧,应使用WrapMode.ClampForever,这将无限期采样最后一帧,直到你手动停止动画。

动画
用户界面(UI)