3D 模型动画
如何为场景中的 3D 模型制作动画
3D 模型中的 .glTF 和 .glb 格式可以包含任意数量的动画。动画通过指定一系列 关键帧 ,这些关键帧按时间排列,然后网格会从一个姿势平滑过渡到另一个姿势,以模拟连续运动。
大多数 3D 模型动画都是 骨骼动画。这些动画会把模型的复杂几何结构简化为“火柴人”,将网格中的每个顶点连接到最近的 骨骼 在 骨架。建模者将骨架调整为不同姿势,网格则伸展和弯曲以跟随这些动作。
作为替代, 顶点动画 无需骨架即可为模型添加动画。这些动画直接指定模型中每个顶点的位置。Decentraland 也支持这些动画。
参见 动画 ,了解如何为 3D 模型创建动画。请阅读 Shape 组件 ,了解如何将 3D 模型导入场景的说明。
检查 3D 模型是否包含动画
并非所有 glTF 文件都包含动画。要查看是否有可用动画,你可以执行以下操作:
如果使用 VS Code(推荐),安装 GLTF Tools 扩展,并在其中查看 glTF 文件的内容。
打开 Babylon Sandbox 网站,然后将 glTF 文件(以及任何 .jpg 或 .bin 依赖项)拖到浏览器中。
打开 .glTF 文件,用文本编辑器打开并向下滚动直到找到 "animations":.
自动播放
如果 3D 模型包含任何动画,默认行为是始终循环播放其中第一个动画。
要避免这种行为,请向拥有该模型的实体添加一个 动画器 组件,然后显式处理动画播放。如果实体中存在一个 动画器 组件,则所有动画默认处于 playing: false 状态,需要手动播放。
显式处理动画
一个 动画器 组件用于访问实体的所有动画,并可用于显式指示实体播放或停止某个动画。 动画器 组件包含一个由 状态组成的数组,这个列表必须为 3D 模型可执行的每个动画都包含一个对象。单个 动画器 可以包含任意数量所需的状态。
每个 state 对象会跟踪动画当前是否正在播放。
import { Animator } from "@dcl/sdk/ecs"
获取动画
通过 动画器 按名称从 .Animator.getClip() 函数中获取一个片段。此函数返回动画状态对象的可变版本。
Animator.getClip 需要以下参数:
实体:你要查询的实体的动画器组件。clipName:你要获取的片段名称字符串。
Animator.getClip 获取动画状态的可变版本,因此你可以自由修改该函数返回的值。
播放动画
该 .playing 字段决定动画当前是否正在播放。请注意,单个 3D 模型中可以同时播放多个动画。
使用 Animator.playSingleAnimation() 函数作用于一个 AnimationState 对象。
如果该实体正在播放任何其他动画, Animator.playSingleAnimation 会停止它们。
Animator.playSingleAnimation 需要以下参数:
实体:你要查询的实体的动画器组件。clipName:你要播放的片段名称字符串。resetCursor: (可选) 如果 true,它会从头开始播放动画,即使该动画之前已暂停。如果 false,它将从暂停的位置继续播放动画。默认值: true.
下表总结了 Animator.playSingleAnimation() 在不同的 resetCursor 属性取值下的表现:
resetCursor = false
resetCursor = true (默认)
当前正在播放
无影响。
从头播放。
已暂停
从最后播放的帧继续。
从头播放。
已结束(非循环)
从头播放。
从头播放。
循环动画
默认情况下,动画会循环播放,永远重复。
通过设置 loop 属性在 state 对象。
如果 loop 设置为 false,动画只播放一次,然后停止,并停留在最后一帧的姿势上。
停止动画
要停止实体正在播放的所有动画,请使用 Animator.stopAllAnimations().
Animator.stopAllAnimations 需要以下参数:
实体:你要查询的实体的动画器组件。resetCursor: (可选) 如果 true,它会恢复到动画第一帧的姿势。如果 false,则会停留在当前姿势并保持暂停。默认值: true.
当非循环动画播放结束后,默认情况下 3D 模型会保持在它最后的姿势。 shouldReset 属性控制当已停止的动画再次播放时会发生什么:如果 true,每当动画从停止切换为播放时,都会将其恢复到初始状态(第一帧;如果以负的 速度播放,则为最后一帧)。如果 false (默认),它将从之前停止的位置继续。
你也可以随时使用 Animator.stopAllAnimations() ,将姿势显式重置为动画的第一帧。
检测动画何时结束
当非循环动画播放结束时,运行时会将该动画状态的 playing 属性重置回 false。你的场景代码可以读取此值来判断动画何时结束,例如紧接着串联另一个动画。
处理多个动画
如果一个 3D 模型打包了多个动画,一个 动画器 组件就可以处理它们全部。
在上面的示例中,两个动画分别由不同的 state 对象处理,然后它们都被分配到同一个 动画器 组件。
动画中的每根骨骼一次只能受一个动画影响,除非这些动画有一个 权重 ,其总和为 1 或更少。
如果一个动画只影响角色的腿,而另一个只影响角色的头部,那么它们可以同时播放,没有问题。但如果它们都影响角色的腿,那么你必须要么一次只播放一个,要么以更低的 权重 值列表。
如果在上面的示例中, bite 动画只影响鲨鱼的嘴部,而 swim 动画只影响鲨鱼脊柱的骨骼,那么它们就可以同时播放。
动画速度
通过更改 速度 属性来改变动画的播放速度。速度值默认是 1。
将速度设为小于 1 可减慢播放,例如设为 0.5 表示以一半速度播放。将其设为大于 1 可加快播放,例如设为 2 表示以两倍速度播放。
动画权重
该 权重 属性允许单个模型同时执行多个动画,通过计算动画中所有运动的加权平均值。 权重 决定该动画在平均计算中占据多大比重。
默认情况下, 权重 等于 1。 权重 不能高于 1.
该 权重 实体中所有活动动画的值应始终加起来为 1。如果总和小于 1,加权平均在剩余部分的计算中将使用骨架的默认姿势。
例如,在上面的代码示例中,我们正在播放 swim 动画,它只有一个 权重 为 0.2。这种游泳动作会相当细微:只有动画定义强度的 20%。剩余 80% 的计算会取自骨架的默认姿势。
该 权重 属性可以以有趣的方式使用,例如 权重 属性 swim 可以按鲨鱼游动的速度成比例设置,这样你就不需要为快慢游动创建多个动画。
你也可以在开始和停止动画时逐渐改变 权重 值,让过渡更自然,并避免从默认姿势跳到动画的第一个姿势。
最后更新于