中EN
概念页

动画管线与动作状态机

Animation Pipeline & Action State Machines

低层动画管线把片段和混合规格变成局部姿势、全局姿势和蒙皮矩阵调色板;其上的动作状态机 (ASM) 给游戏代码提供"按状态驱动动画"的接口。每个状态是任意复杂的片段混合,跟踪当前所有片段的方式有扁平加权平均和混合树两种;过渡用数据驱动的过渡矩阵描述,控制参数通过节点搜索、命名变量或控制结构体暴露给代码(GEA4 卷 II 13.9–13.10)。

动画管线的六个阶段

对每个动画中的角色或物体(卷 II 13.9):

  1. 片段解压与姿势提取:每个片段在当前时间提取一个局部姿势,可以是全身、部分(关节子集)或差分姿势。
  2. 姿势混合:全身 lerp、部分骨骼 lerp、叠加混合,输出一个完整的局部姿势;只有一个片段时跳过。见 动画混合。
  3. 全局姿势生成:遍历层级连乘局部姿势。
  4. 后处理(可选):IK、布娃娃、程序化动画,见 动画约束与后处理。
  5. 重算全局姿势:很多后处理以全局姿势为输入、输出局部姿势,之后需重算;不需要全局姿势的后处理可以放在 2 和 3 之间,省掉重算。
  6. 矩阵调色板生成:每个关节的全局姿势乘缓存的逆绑定姿势,得到交给渲染器的蒙皮矩阵,见 顶点混合与蒙皮。
flowchart LR
  IN["输入:局部时钟、片段、骨骼、混合规格"] --> D["解压与姿势提取"]
  D --> B["姿势混合"]
  B --> G["全局姿势计算"]
  G --> P["后处理 IK/布娃娃"]
  P --> G2["重算全局姿势"]
  G2 --> K["蒙皮矩阵计算"]
  K --> OUT["输出:局部姿势、全局姿势→玩法系统;矩阵调色板→渲染引擎"]

上图按 GEA 图 13.48 的阶段顺序绘制;后处理钩子位于全局姿势之后、调色板生成之前。

动作状态机

角色的动作(站、走、跑、跳)最好用有限状态机建模,即动作状态机 (ASM)。它位于动画管线之上,几乎所有高层游戏代码都通过它驱动动画(卷 II 13.10)。通用 FSM 见 状态模式与有限状态机。

  • 每个状态对应一个任意复杂的混合:idle 可以只是一个全身片段;"跑"是半圆方向混合;"边跑边射击"再加瞄准用的叠加或部分混合、看向用的眼头肩混合、控制步态和脚距的叠加,以及增加"人味"的随机变化。
  • 状态 A→B 过渡时,两个状态的输出姿势通常交叉淡入淡出。
  • 状态层:身体不同部分可同时做不同的事(跑、瞄准射击、面部说台词),而且彼此不完全同步:头先转,然后是肩、髋,最后是腿,传统动画称之为预备动作 (anticipation)。做法是多个独立状态机各占一层,各层输出再混合成最终姿势。GEA 图 13.49 的例子:基础层负责全身姿态和移动,变化层叠加差分片段增加多样性,两个手势层(一个叠加、一个部分混合)负责瞄准和指向。

扁平加权平均

引擎维护一张当前所有权重非零片段的扁平列表,对每个关节的平移、四元数(当作四维向量)、缩放做 N 点加权平均(卷 II 13.10.1):

vavg=∑iwivi∑iwiv_{avg}=\frac{\sum_i w_iv_i}{\sum_i w_i}

权重归一化后就是 ∑wivi\sum w_iv_i;N=2 时退化为 lerp。

  • 补充(GEA 此处只说把四元数“当作四维向量”平均):加权和一般不是单位四元数,平均后要重新归一化(即 nlerp 的推广);并且 qq 与 −q-q 表示同一旋转,求和前需把各四元数翻到同一半球(与参考四元数点积为负就取反),否则会抵消甚至得到接近零的结果。见 四元数 和 动画混合 中的 slerp 符号说明。这种平均只在各旋转彼此接近时是好的近似。
  • OGRE:Ogre::Entity 聚合 AnimationStateSet,其中每个 AnimationState 记片段名、局部时钟 mTimePos、权重 mWeight、是否启用、是否循环。OGRE 没有播放速率概念,只能靠缩放传给 addTime() 的时间来变速(卷 II 13.10.1.1)。
  • Granny:同样是扁平加权平均并自动归一化权重;长处在时间处理,使用全局时钟、支持任意次数循环和负速率倒放(卷 II 13.10.1.2)。
  • 交叉淡入淡出:简单情况就是升 wBw_B、降 wAw_A。从一个复合混合过渡到另一个(如走 = ABC 三路平均,跳 = DE 两路)时,要保持组内相对权重:源组权重乘 (1−λ)(1-\lambda),目标组乘 λ\lambda,例如 wA=(1−λ)0.2w_A=(1-\lambda)0.2…wE=λ 0.66w_E=\lambda\,0.66(式 13.20)。这要求在扁平数组之外额外维护片段分组的元数据(卷 II 13.10.1.3)。

混合树

混合树是编译原理中的表达式树(语法树):内部节点是混合运算(非终结符),叶节点是片段(终结符)(卷 II 13.10.2)。

节点说明
二元 lerp两个输入、一个 β\beta
一维通用混合n 个输入;对给定 bb 总能化成相邻两个片段的二元 lerp
二维 lerp级联的二元 lerp
叠加二元,但输入不可交换:一个是普通姿势,另一个是差分姿势,结果是普通姿势;所以叠加输入必须是叶节点,叠多个差分要级联
分层各层当前状态的树合并成一棵"超级树 (über tree)"
交叉淡入淡出在源、目标两棵树的根之间临时插一个二元 lerp 节点,λ\lambda 从 0 到 1,完成后撤掉该节点和源树

和扁平加权平均相比,混合树上的交叉淡入淡出更直观:无论是片段到片段还是复合混合到复合混合,做法都一样(卷 II 13.10.2.6)。

状态与混合树的数据驱动规格

  • 目标是快速迭代:增删改状态并很快看到结果。原子节点只需四种:片段、二元 lerp、二元叠加,可能还有三元(三角形)lerp;常用组合可预定义为复合节点(N 维线性混合、足球运球、射击、格斗招式等)。GEA 作者认为用文本还是图形编辑器对最终质量影响不大,关键是改了能很快看到效果(卷 II 13.10.3)。
  • Naughty Dog(《神秘海域》《最后生还者》):用定制的 Scheme 写状态(与公司的 Lisp 渊源有关),分 simple(单片段)和 complex(任意 lerp/叠加树)两类:
(define-state complex
  :name "move-b-to-f"
  :tree (anim-node-lerp
          (anim-node-additive
            (anim-node-additive (anim-node-clip "move-f") (anim-node-clip "move-f-look-lr"))
            (anim-node-clip "move-f-look-ud"))
          (anim-node-additive
            (anim-node-additive (anim-node-clip "move-b") (anim-node-clip "move-b-look-lr"))
            (anim-node-clip "move-b-look-ud"))))

快速迭代靠四个工具:游戏内动画查看器;命令行工具热重编、热重载动画脚本;记录每个角色最近几秒的全部状态转换,可暂停后倒带排查;以及在 Maya 里改动画几乎即时更新到游戏里的实时更新工具(卷 II 13.10.3.1)。数据定义语言的背景见 引擎配置系统,游戏内工具见 游戏内调试工具。

  • UE5:GEA 列出骨架编辑器(绑定、给关节加插槽 socket,即其他引擎的挂接点)、骨骼网格体编辑器、动画编辑器(导入、压缩、片段时间设置,组合混合空间,创建动画蒙太奇)、动画蓝图编辑器(用蓝图控制动画状态机)和物理编辑器(布娃娃刚体层级)(卷 II 13.10.3.2)。详见 动画蓝图与动画系统。

过渡

  • 种类:源末姿势与目标首姿势完全一致时可直接切换;否则交叉淡入淡出;交叉淡入淡出做不出来的(从躺地到站起)用过渡状态,它只在过渡中使用、从不作为稳态节点,但作为完整状态可以包含任意混合树(卷 II 13.10.4.1)。
  • 参数:源与目标状态、类型(立即 / 交叉淡入淡出 / 过渡状态)、时长、缓入缓出曲线类型、过渡窗口(只在源动画局部时间的某段区间内允许,例如出拳挥到后半段才能接受击反应)(卷 II 13.10.4.2)。
  • 过渡矩阵:n 个状态最多 n2n^2 种过渡,实际矩阵很稀疏(死亡态不能转出,开车不能直接转游泳),而且一个过渡规格可被许多状态对复用(卷 II 13.10.4.3)。
  • 《荣誉勋章:血战太平洋》的通配符过渡:源、目标名可含 *,先定义全局默认 from="*" to="*",再按类别细化,直到具体状态对(卷 II 13.10.4.4):
<trans from="*" to="*" type=frozen duration=0.2>
<trans from="walk*" to="run*" type=smooth duration=0.15>
<trans from="*prone" to="*get-up" type=smooth duration=0.1 window-start=2.0 window-end=7.5>
  • 《神秘海域》的一等公民过渡:如果高层代码按目标状态名请求过渡,就得知道状态名和哪些过渡合法。Naughty Dog 把过渡变成有名字的一等实体:每个状态列出合法过渡,名字标准化(叫 "walk" 的过渡总是去某种走路状态),代码按过渡名请求,找不到就失败。transition-group 复用一组过渡,transition-end 指定局部时间到头时的过渡。好处是状态图结构可以改,C++ 不用动:十种走路状态都定义叫 "jump" 的过渡,先都指向一个通用跳跃状态,再逐步改成各自的跳跃或插入过渡状态,只要过渡名不变(卷 II 13.10.4.4)。

控制参数

  • 扁平加权平均:接口简单,但控制代码要按名字查每个片段并亲自调权重(比如为斜向跑去调 StrafeLeft、RunForward、StrafeRight、RunBackward 四个权重),繁琐难读。
  • 混合树:片段天然按功能分组,但参数埋在树里,代码需要先验地知道树结构。
  • 常见解法:节点搜索(给关键节点起名如 "HorizAim",按名查找)、命名变量(参数按名字查)、控制结构体(一个浮点数组或 C 结构体存全部参数,节点按成员、名字或索引绑定)(卷 II 13.10.5)。

与 UE5 的对照

GEA 概念UE5 对应差异
状态层动画蓝图中的插槽 (Slot) 与上下半身分层UE5 文档用插槽组让上下半身同时播放不同蒙太奇(Animation Montage)
过渡参数与稀疏矩阵状态机转换规则、导管、状态别名UE5 转换是单向连线;状态别名让一组状态共享同一套规则和混合时长(State Machines),作用上接近 MOHPA 的通配符默认过渡
过渡状态状态机中的普通状态UE5 文档未单列"过渡状态"类型(这一对应是归纳)
命名变量 / 控制结构体事件图更新、动画图读取的变量见 动画蓝图与动画系统

GEA 原书中的问题

  • 13.10.3.2 的标题是 Unreal Engine 5,但文中说片段"UE4 称为 Sequences",配图也是"Unreal Engine 4 animation Blueprints editor",是从旧版沿用的文字和截图。
  • 同节说动画蒙太奇用来定义游戏内过场 (in-game cinematics)。UE5 文档把蒙太奇描述为把多个动画序列组合成一个资产并由蓝图控制播放、可分段跳转(用于连招、换弹等玩法动作)(Animation Montage);UE5 中制作过场的工具是 Sequencer 过场动画(Unreal Engine Sequencer Movie Tool Overview)。两种说法并列,以引擎文档为准。
  1. Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
  2. Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 13 章 13.9–13.10 节
  3. State Machines
  4. Animation Montage
  5. Unreal Engine Sequencer Movie Tool Overview

相关页面

游戏开发动画混合Animation Blending动画混合把两个或多个输入姿势合成一个输出姿势。基本工具是对每个关节的局部 SRT 分别做 lerp(旋转用 nlerp 或 slerp);在此之上有时间插值、交叉淡入淡出、方向移动、一维/二维混合空间、部分骨骼混合和叠加混合(差分片段)。前几种都是加权平均,叠加混合则是"加上一段变化"(GEA4 卷 II 13.6)。游戏开发骨骼、姿势与动画片段Skeletons, Poses & Animation Clips角色动画系统的数据核心是三样东西:骨骼(关节层级)、姿势(每个关节的 SRT 变换)和动画片段(姿势随局部时间变化的采样)。GEA 把各种动画方法看成对"逐点控制表面"这一理想的不同压缩方式;骨骼蒙皮用少量关节驱动大量顶点,是今天最主流的方案(GEA4 卷 II 13.1–13.4)。游戏美术顶点混合与蒙皮Vertex Blending & Skinning顶点混合(也叫线性混合蒙皮、enveloping、骨骼子空间变形)让一个顶点受多根骨骼的变换影响,按权重混合结果,使关节处的"皮肤"连续弯曲。它非常适合在 GPU 上执行;主要缺点是关节折叠、扭转和自相交,可用双四元数蒙皮等方法改善。游戏开发动画约束与后处理Animation Constraints & Post-Processing片段混合之后、渲染之前,动画系统常常还要修改姿势,这叫动画后处理:程序化动画、逆向运动学 (IK)、布娃娃。另一大类需求是约束:把武器挂在手上(挂接点)、让多个角色对齐演出(参考定位器)、手抓物体(手部 IK)、脚不滑步(根运动提取与脚部 IK),以及注视、掩体、穿越辅助等(GEA4 卷 II 13.7、13.11)。游戏开发状态模式与有限状态机State Pattern & Finite State Machines状态模式 (State Pattern) 把对象“依赖状态的行为”分散到各个状态类中,对象只持有指向当前状态的指针并把调用委托给它,状态切换就是换指针。它是实现有限状态机 (Finite State Machine, FSM) 的一种方式。FSM 能用很强的结构约束理清一团乱麻的标志位代码;状态组合爆炸、需要复用和需要“回到之前状态”时,分别用并发状态机、分层状态机和下推自动机来扩展。游戏开发 · UE5动画蓝图与动画系统Animation Blueprint & Animation SystemUE5 角色动画以动画蓝图 (Animation Blueprint) 为核心:它每帧为骨骼网格体 (Skeletal Mesh) 计算最终姿势。动画蓝图内部用状态机 (State Machine) 组织“何时播什么”,用混合空间 (Blend Space) 按速度、方向等参数连续混合,用蒙太奇 (Animation Montage) 在插槽 (Slot) 中插播攻击、交互等一次性动作,用 Control Rig 做程序化骨骼控制(如贴地)。算出的骨骼姿势最终交给蒙皮 (Skinning) 驱动顶点。游戏开发 · UE5运动匹配Motion Matching运动匹配 (Motion Matching) 是 Pose Search 插件提供的动画蓝图节点,可以作为状态机和混合空间的动态替代:每次用 Schema 定义的通道(骨骼位置/速度、轨迹采样点等)构造查询,在数据库里的大量动画中找出代价最低的姿势,而不需要手工编写过渡和混合逻辑。增加动画数据就能提高保真度;代价是内存和查询开销会随通道、采样数和采样率增加。游戏开发引擎配置系统Engine Configuration游戏引擎总会积累大量可配置选项:有的通过选项菜单暴露给玩家(画质、音量、手柄设置),有的只供开发团队使用、发售前隐藏或去除(如玩家最大行走速度在开发期可调、发售前改成硬编码)。GEA 讨论选项的存取方式(文本文件、压缩二进制、注册表、命令行、环境变量、在线档案)、全局与每用户选项,以及 Quake cvar、OGRE、Naughty Dog 三个真实例子。游戏开发游戏内调试工具In-Game Debugging Tools各子系统(渲染、动画、碰撞、物理、音频、网络、玩家机制、AI……)都有大量配置项,能在游戏运行时调整而无需改代码、重新编译链接再运行,可大幅节省调试和搭建关卡/玩法的时间。GEA 介绍支撑这一点的几类游戏内工具:游戏内菜单(及 Dear ImGui 等第三方 GUI)、游戏内控制台、调试摄像机与暂停/慢动作、作弊功能、截图与录像。(卷 I 10.3–10.7 节)游戏开发动画压缩Animation Compression未压缩的动画每关节每样本最多 10 个 32 位浮点通道,数据量巨大。GEA 列出的压缩手段按力度递增:省略无用通道、量化(如 16 位 RL 编码)、降低采样率或省略近似线性的关键帧、用 B 样条拟合曲线、小波压缩,以及最根本的:只把需要的片段放进内存(选择性加载与流式加载)(GEA4 卷 II 13.8)。游戏开发物理引擎与游戏的集成Integrating a Physics Engine into a Game碰撞/物理世界里的刚体只是抽象的数学描述,要通过游戏对象这个中枢,间接连到屏幕上的视觉表现。刚体按谁驱动分三类:物理驱动、游戏驱动(Havok 称 key framed)、固定;Havok 用可在运行时切换的"运动类型"统一表示。每帧更新有固定顺序:先更新游戏驱动刚体、幻影、力、冲量和约束,再步进模拟,然后回读物理驱动对象、查询幻影、执行投射查询。物理宜用恒定的 1/30 或 1/60 秒时间步。GEA 还逐一讨论了子弹、手雷、爆炸、可破坏物、角色移动、相机碰撞和布娃娃的实际做法(GEA4 卷 II 14.5–14.6)。游戏开发游戏对象的实时更新Updating Game Objects in Real Time游戏对象更新就是根据上一时刻状态 Si(t − Δt) 求出当前状态 Si(t)。"每帧对每个对象调一次虚函数 Update(),并在里面顺带更新它的动画、物理、渲染组件"的简单做法在商业引擎里行不通:底层子系统需要批量更新才能高效,而对象之间、子系统之间又有依赖顺序。GEA 介绍的对策依次是:子系统由游戏循环直接批量更新、对象只操纵子系统中的"代理状态";在帧内多个阶段挂回调;按依赖森林把对象分桶,逐桶运行完整的分阶段更新(Naughty Dog 的做法);并用状态缓存和时间戳对付更新过程中的状态不一致和一帧延迟(GEA4 卷 II 17.6)。游戏开发 · UE5Sequencer 过场动画SequencerSequencer 是 UE 的多轨道过场动画编辑器:在 Level Sequence 资产里添加轨道和关键帧,来驱动物体、角色和相机。数据存放在 Level Sequence 资产(内容浏览器中),由关卡里的 Level Sequence Actor 把它绑定到关卡并播放。Camera Cuts 轨道在播放时接管相机;最终的高质量输出通过 Movie Render Queue 完成,可以搭配路径追踪器。游戏数学四元数Quaternion单位四元数可以紧凑地表示任意三维旋转,与轴-角表示互相转换很简单,并能做稳定、匀速的朝向插值(slerp),这些都是欧拉角做不好的。它可以高效地转换为矩阵以便与其他变换合并。游戏美术游戏动画技术基础Game Animation Technical Foundations《GAME ANIM》第 5 章按基础→中级→高级梳理游戏动画师必须掌握的引擎侧概念:三类动画形态(循环 / 线性 / 过渡)、骨骼导出与数值运算、样条与碰撞移动、FK/IK,以及状态机、参数化混合、局部动画、叠加层、布娃娃,再到全身 IK、Look-At、混合形状与程序化系统。本页只收录书中实际讲到的内容,并与引擎架构页互链。游戏美术玩法动画Gameplay Animation第 9 章从 Three Cs(角色 Character、相机 Camera、控制 Control)出发,系统讲地面移动(idle、循环、原地 vs 向前、 strafing、起停过渡)、跳跃与攀爬度量、以及攻击/受击的预备—响应—可读性与连招切割。这是五大基本功在「每帧可玩」场景下的落地清单。游戏美术动作捕捉与 Motion MatchingMotion Capture & Motion Matching第 11 章回答「要不要动捕」、光学/惯性/深度/表演捕捉差异、拍摄规划与演员工作,以及后期的重定时、姿势夸张、偏移姿势、循环混合;并专节讲 Motion Matching 的适用边界与第三人称地面移动的 shot list。引擎实现细节见已有页 运动匹配(UE Pose Search);本页保留书中制作向观点。游戏美术游戏动画五大基本功Five Fundamentals of Game AnimationDisney 的「动画十二原则」面向线性媒介;游戏动画还必须在玩家每秒级输入下既好看又好控。Jonathan Cooper 在《GAME ANIM》第 2 版中提出与之互补的五大基本功:手感 (Feel)、流畅性 (Fluidity)、可读性 (Readability)、上下文 (Context)、优雅 (Elegance)——目标是角色不仅「看起来对」,还要「操控起来对」。

被这些页面引用2 篇

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原