Unity3d:动画脚本(旧版)

推荐:将NSDT场景编辑器加入你的3D工具链
3D工具集:NSDT简石数字孪生

动画脚本(旧版)

Unity 的动画系统允许您创建精美的动画皮肤角色。动画系统支持动画混合,混合,添加动画,步行循环时间同步,动画图层
,控制动画播放的所有方面(时间、速度、混合权重),网孔
剥皮
每个顶点有 1、2 或 4 块骨头,并支持基于物理的布娃娃和程序动画。要获得最佳结果,建议您在建模优化角色页面上阅读在 Unity 中创建具有最佳性能的绑定角色的最佳实践和技术。

制作动画角色涉及两件事;在世界中移动它并相应地制作动画。如果要了解有关移动字符的更多信息,请查看角色控制器页面。本页重点介绍动画。角色的实际动画是通过 Unity 的脚本界面完成的。

您可以下载显示预设置动画角色的示例演示。了解此页面上的基础知识后,您还可以看到动画脚本界面。

动画混合

在当今的游戏中,动画混合是确保角色具有流畅动画的基本功能。动画师创建单独的动画,例如,步行循环、跑步循环、空闲动画或拍摄动画。在游戏过程中的任何时候,您都需要能够从空闲动画过渡到步行周期,反之亦然。当然,您希望过渡平稳并避免运动中的突然抖动。

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

我们的第一步是使角色在空闲和行走动画之间平滑地融合。为了使脚本编写者的工作更轻松,我们首先将动画的环绕模式设置为 Loop。然后我们将关闭自动播放以确保我们的脚本是唯一播放动画的脚本。

我们的第一个角色动画脚本非常简单;我们只需要一些方法来检测我们的角色移动速度,然后在行走和空闲动画之间淡入淡出。对于这个简单的测试,我们将使用标准输入轴:-

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

要在项目中使用此脚本:-

  1. 使用 Assets 创建 Javascript 文件> 创建 > Javascript
  2. 将代码复制并粘贴到其中
  3. 将脚本拖到角色上(它需要附加到游戏对象
    有动画)

当您点击播放按钮时,当您按住向上箭头键时,角色将开始原地行走,并在您释放它时返回到空闲姿势。

动画图层

图层是一个非常有用的概念,它允许您对动画进行分组并确定权重的优先级。

Unity 的动画系统可以混合任意数量的动画剪辑
如你所愿。您可以手动分配混合权重,也可以仅使用动画。CrossFade(),它将自动对权重进行动画处理。

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

假设您有一个步行周期和一个跑步周期,两者的权重均为 1 (100%)。当 Unity 生成最终动画时,它将规范化权重,这意味着步行周期将为动画贡献 50%,跑步周期也将贡献 50%。

但是,当有两个动画正在播放时,您通常希望优先考虑哪个动画获得最大的权重。当然可以确保手动将重量总和达到 100%,但为此目的使用图层更容易。

分层示例

例如,您可能有一个拍摄动画、一个空闲和一个步行循环。步行和空闲动画将根据玩家的速度混合,但当玩家射击时,您可能只想显示射击动画。因此,拍摄动画本质上具有更高的优先级。

最简单的方法是在拍摄时继续播放步行和空闲动画。为此,我们需要确保拍摄动画位于比空闲和行走动画更高的层中,这意味着射击动画将首先接收混合权重。仅当拍摄动画未使用全部 100% 的混合权重时,步行和空闲动画才会获得权重。因此,当交叉淡入淡出拍摄动画时,权重将从零开始,并在短时间内变为 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");
}

默认情况下为动画。播放()动画。CrossFade() 将停止或淡出同一图层中的动画。在大多数情况下,这正是我们想要的。在我们的拍摄、空闲、运行示例中,播放空闲和运行不会影响拍摄动画,反之亦然(您可以使用可选参数将此行为更改为动画。交叉淡入淡出,如果你愿意)。

动画混合

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

通过在给定的 AnimationState 上调用 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;
}

提示:使用加法动画时,还必须在加法动画中使用的每个变换上播放一些其他非加法动画,否则动画将添加到最后一帧的结果之上。这肯定不是你想要的。

按程序对角色进行动画处理

有时你想按照程序化地为角色的骨骼制作动画。例如,您可能希望角色的头部查看 3D 空间中的特定点,最好由跟踪目标点的脚本处理。幸运的是,Unity 使这变得非常简单,因为骨骼只是驱动蒙皮网格体的变换。因此,您可以从脚本中控制角色的骨骼,就像游戏对象的变换一样。

需要知道的一件重要事情是,动画系统在 Update() 函数之后和 LateUpdate() 函数之前更新转换。因此,如果你想做一个 LookAt() 函数,你应该在 LateUpdate() 中这样做,以确保你真的覆盖了动画。

布娃娃以相同的方式创建。你只需要附加刚体
,角色关节
和胶囊对撞机
到不同的骨头。然后,这将为您的皮肤角色提供物理动画。

动画播放和采样

本节介绍在引擎播放 Unity 中的动画时如何对其进行采样。

动画剪辑通常以固定的帧速率创作。例如,您可以在 Autodesk 3ds Max® 或 Autodesk®® Maya® 中以 60 的帧速率创建动画。每秒帧数
(帧率)。在 Unity 中导入动画时,导入器会读取此帧速率,因此导入动画的数据也会以 60 采样帧率
.

但是,游戏通常以可变帧速率运行。某些计算机上的帧速率可能高于其他计算机上的帧速率,并且根据视图的复杂性,帧速率也可能从一秒到下一秒而变化。照相机
在任何给定的时刻都在看。基本上,这意味着我们不能对游戏运行的确切帧速率做出任何假设。这意味着,即使动画以 60 fps 创作,也可能以不同的帧速率播放,例如 56.72 fps 或 83.14 fps,或几乎任何其他值。

因此,Unity 必须以可变帧速率对动画进行采样,并且无法保证其最初设计的帧速率。幸运的是,3D计算机图形的动画不是由离散帧组成,而是由连续曲线组成。可以在任何时间点对这些曲线进行采样,而不仅仅是在与原始动画中的帧相对应的时间点进行采样。事实上,如果游戏以比创作动画时更高的帧速率运行,则动画在游戏中看起来实际上会比在动画软件中更流畅、更流畅。

出于大多数实际目的,您可以忽略 Unity 以可变帧速率对动画进行采样的事实。但是,如果您的游戏逻辑依赖于将转换或属性动画转换为非常具体的配置的动画,那么您需要注意重新采样发生在场景
.例如,如果您有一个动画,该动画将对象从 0 到 180 度旋转超过 30 帧,并且您希望从代码中知道它何时到达一半,则不应通过在代码中使用条件语句来检查当前旋转是否为 90 度。由于 Unity 根据游戏的可变帧速率对动画进行采样,因此它可能会在旋转刚好低于 90 度时对其进行采样,下次在旋转达到 90 度之后进行采样。如果需要在到达动画中的特定点时收到通知,则应改用 AnimationEvent。

另请注意,由于可变帧率采样,使用 WrapMode.Once 播放的动画可能不会在最后一帧的确切时间采样。在游戏的一帧中,动画可能会在动画结束之前进行采样,而在下一帧中,时间可能已超过动画的长度,因此禁用了动画,不再进一步采样。如果您绝对需要精确地采样动画的最后一帧,则应使用 WrapMode.ClampForever,它将无限期地对最后一帧进行采样,直到您自己停止动画。

3D建模学习工作室整理翻译,转载请标明出处!

上一篇:Unity3d:动画 (mvrlink.com)

下一篇:Unity3d:导入开发工具包 (mvrlink.com)

NSDT场景编辑器 | NSDT 数字孪生 | GLTF在线编辑器 | 3D模型在线转换 | UnrealSynth虚幻合成数据生成器 | 3D模型自动纹理化工具
2023 power by nsdt©鄂ICP备2023000829号