中EN
概念页

骨骼、姿势与动画片段

Skeletons, Poses & Animation Clips

角色动画系统的数据核心是三样东西:骨骼(关节层级)、姿势(每个关节的 SRT 变换)和动画片段(姿势随局部时间变化的采样)。GEA 把各种动画方法看成对"逐点控制表面"这一理想的不同压缩方式;骨骼蒙皮用少量关节驱动大量顶点,是今天最主流的方案(GEA4 卷 II 13.1–13.4)。

四类角色动画

方法做法优点问题
赛璐珞/精灵动画 (Cel / Sprite)快速轮播一组位图;可循环的称为循环动画,如跑步循环 (run cycle)简单只适合 2D 或远景(Doom 的怪物就是朝向相机的四边形 + 动画纹理)
刚性层级动画 (Rigid Hierarchical)角色由刚性部件组成,按层级约束适合机器人、机械关节处"开裂"
逐顶点动画与变形目标 (Per-Vertex / Morph Target)逐顶点导出运动;变形目标只存少数极端姿势,运行时 lerp任意形变;面部(约 50 块肌肉)常用逐顶点数据量太大,实时少用
蒙皮动画 (Skinned)隐藏的骨骼驱动一张连续的皮肤网格,每个顶点可受多个关节加权影响兼具形变能力与刚性层级的效率见 顶点混合与蒙皮

GEA 说蒙皮动画最早由《超级马里奥 64》这类游戏使用,至今仍是游戏和电影的主流(侏罗纪公园的恐龙、Solid Snake、咕噜、Nathan Drake、巴斯光年、Marcus Fenix、Joel 等都全部或部分用蒙皮动画制作)。补充:《超级马里奥 64》游戏内的马里奥模型是一组刚性网格段,每个顶点只属于一个骨头,只在父子骨头交界处共享顶点来拉伸(N64 只支持"二值"蒙皮,见 fast64 SM64 导出工具 README),还不是现代那种逐顶点多关节加权的皮肤;标题画面可拖动的马里奥脸(Goddard 子系统)才是加权蒙皮。也有工作室用含数百关节的面部绑定替代变形目标,或两者结合:关节给出主姿势,变形目标做细微修正(卷 II 13.1.3–13.1.4)。

动画方法即数据压缩

最灵活的系统是控制表面上每个无穷小点,数据量无限。只动顶点是第一层压缩;变形目标再约束顶点只能沿预定义位置之间的直线移动;骨骼动画则约束大量顶点跟随少量关节。挑选方法时可以像挑视频编码一样,选在可接受瑕疵下压缩率最高的那种。肢体基本像刚体,骨骼压缩率高;面部各顶点运动更独立,要逼真需要的关节数接近顶点数,压缩优势消失,这是面部常用变形目标的原因之一(另一个原因是动画师更习惯)(卷 II 13.1.5)。

骨骼

  • 骨骼由关节 (joint) 组成。业界常把 joint 和 bone 混用,但严格说动画师操纵的是关节,"骨头"只是关节之间的空隙;骨盆一个关节连四个子关节,看上去就伸出四根骨头。引擎只关心关节(卷 II 13.2)。
  • 关节编号 0…N−1,每个关节只存父索引,根关节父索引为 −1 之类的无效值。数组中子关节总排在父关节之后,所以 0 号总是根。用 16 位索引引用关节,比按名字引用省空间、查找快(卷 II 13.2.1–13.2.2)。
  • 每个关节通常存:名字(字符串或 32 位哈希 string id,见 字符串与唯一标识符)、父索引、逆绑定姿势矩阵。
struct Joint {
    Matrix4x3   m_invBindPose; // 逆绑定姿势
    const char* m_name;
    U16         m_iParent;     // 父索引,根为 0xFFFF
};
struct Skeleton { U32 m_jointCount; Joint* m_aJoint; };
  • 原书问题(书内前后不一致):GEA 说 16 位关节索引"可以接受每个骨骼最多 65,536 个关节",但同一段代码把 0xFFFF 留作根关节的"无父"标记,所以实际可用的索引最多 65,535 个(0…0xFFFE)。实践中无影响。

姿势

  • 关节姿势是关节相对某参考系的位置、朝向和缩放,用 4×4 / 4×3 矩阵或 SRT(缩放、四元数旋转、平移)表示;骨骼姿势就是全部关节姿势的数组(卷 II 13.3)。
  • 绑定姿势 (bind pose),又叫参考姿势、静止姿势、T 姿势:网格绑定到骨骼之前的姿势,四肢张开便于绑定(卷 II 13.3.1)。
  • 局部姿势:相对父关节,几乎总以 SRT 存储(便于混合)。每个关节其实定义了一个坐标系,即关节空间。数学上关节姿势是一个仿射变换 PjP_j,由平移 TjT_j、3×3 对角缩放矩阵 SjS_j 和 3×3 旋转矩阵 RjR_j 组成,它把关节空间的点变到父空间,记作 Pj→p(j)P_{j\to p(j)}(卷 II 13.3.2)。
  • 关节缩放:有的引擎不允许缩放,有的只允许均匀缩放(一个标量),有的允许非均匀缩放(三元组),几乎没有允许切变的。限制为均匀缩放既省内存,又保证关节的包围球不会变成椭球,简化逐关节的视锥和碰撞测试(卷 II 13.3.2.1)。
  • 局部姿势可看作基变换:Pj→p(j)P_{j\to p(j)} 把关节 jj 空间里表示的点或向量变到父关节空间;反方向(父到子)就是它的逆,Pp(j)→j=Pj→p(j)−1P_{p(j)\to j}=P_{j\to p(j)}^{-1}(卷 II 13.3.2.3)。
  • 允许非均匀缩放时,GEA 把 JointPose 改成 Quaternion m_rot; Vector4 m_trans; Vector4 m_scale;(卷 II 13.3.2.2)。
  • 全局姿势:关节到模型空间的变换,沿层级往根连乘局部姿势,根的父空间定义为模型空间:

Pj→M=∏i=j0Pi→p(i),例:P5→M=P5→4P4→3P3→0P0→MP_{j\to M}=\prod_{i=j}^{0}P_{i\to p(i)},\quad\text{例:}P_{5\to M}=P_{5\to4}P_{4\to3}P_{3\to0}P_{0\to M}

(卷 II 13.3.3,式 13.1)

struct JointPose { Quaternion m_rot; Vector3 m_trans; F32 m_scale; }; // 四元数放首位以保证对齐与紧凑
struct SkeletonPose {
    Skeleton*  m_pSkeleton;
    JointPose* m_aLocalPose;   // 局部姿势
    Matrix44*  m_aGlobalPose;  // 全局姿势
};

动画片段

电影可以把整场戏作为一个连续序列来做;游戏是交互的,角色运动必须拆成成千上万个细粒度的动画片段 (clip):有的循环(走、跑),有的只播一次(投掷、摔倒),有的影响全身,有的只影响局部。例外是非交互段落:游戏内过场 (IGC)、非交互序列 (NIS) 由引擎实时渲染,全动态视频 (FMV) 是预渲染的视频;快速反应事件 (QTE) 是半交互的变体(卷 II 13.4)。引擎内过场工具可参考 Sequencer 过场动画。

局部时间线

  • 每个片段有局部时间 t∈[0,T]t\in[0,T]。动画师只做关键姿势,其余由线性或曲线插值补出,所以时间线是连续的:游戏帧率波动、片段可变速,玩家实际看到的可能是第 1.1、1.9、3.2 帧;负的时间缩放可倒放(卷 II 13.4.1.1)。
  • 时间单位最好用秒(浮点、定点,或计量极小子帧间隔的整数),不要用整数帧计数(卷 II 13.4.1.2)。
  • 帧与样本:GEA 作者用"样本"指时间点,"帧"指 1/30 或 1/60 秒的时段。30 fps 的 1 秒动画有 30 帧、31 个样本。非循环片段 N 帧有 N+1 个样本;循环片段最后一个样本与第一个重合,所以只存 N 个(卷 II 13.4.1.3–13.4.1.4)。
  • 归一化时间(相位) u∈[0,1]u\in[0,1]:同步不同时长的片段很方便。例如从 2 秒的跑循环交叉淡入 3 秒的走循环,令 uwalk=urunu_{walk}=u_{run} 并以相同的归一化速率推进,脚步就能对上(卷 II 13.4.1.5)。

全局时间线与两种时钟

播放片段就是把局部时间线映射到角色的全局时间线 τ\tau 上。已知起始时间 τstart\tau_{start}、播放速率 RR、时长 TT、循环次数 NN(卷 II 13.4.2,式 13.2):

t=(τ−τstart)R,τ=τstart+1Rtt=(\tau-\tau_{start})R,\qquad \tau=\tau_{start}+\tfrac{1}{R}t

  • 不循环:tt 夹到 [0,T][0,T];无限循环:t mod Tt \bmod T;有限循环:先夹到 [0,NT][0,NT] 再  mod T\bmod T。
  • 原书问题:GEA 说取模"用 mod 运算符,即 C/C++ 的 %",但 C/C++ 的 % 只接受整数操作数,浮点时间要用 std::fmod;而 fmod 结果与被除数同号(cppreference:std::fmod、算术运算符),t<0t<0 时会得到负值,需要再加 TT 才落在 [0,T)[0,T)。同理,GEA 图 13.19 用 R=−1R=-1 倒放、局部时间从 t=Tt=T 开始,但式 13.2 的 t=(τ−τstart)Rt=(\tau-\tau_{start})R 在 R<0R<0 时给出负的 tt,直接夹到 [0,T][0,T] 会一直停在 0;倒放时应写成 t=T+(τ−τstart)Rt=T+(\tau-\tau_{start})R(或先取模再按上面处理负数)。
  • 局部时钟:每个片段自己推进时间(乘以 RR),简单直观。
  • 全局时钟:角色有一个全局时钟,片段只记 τstart\tau_{start}。同步变得很简单:玩家出拳与 NPC 受击由不同子系统触发,用局部时钟时取决于更新顺序会差一帧(经事件系统还会更晚);用全局时钟只要把受击动画的 τstart\tau_{start} 设成出拳的即可,不管哪段代码先跑(卷 II 13.4.3)。所有角色共享一个主时钟即可保证时钟一致。时钟与时间线的通用讨论见 游戏时间线与时钟。

简单数据格式、通道与元通道

  • 从 Maya 以 30 或 60 Hz 采样导出,每关节每样本存 S(1 或 3 个分量)、Q(4)、T(3),即最多 10 个通道(卷 II 13.4.4)。
struct AnimationSample { JointPose* m_aJointPose; };
struct AnimationClip {
    Skeleton* m_pSkeleton;          // 实际引擎中常用骨骼唯一 id
    F32 m_framesPerSecond; U32 m_frameCount;
    AnimationSample* m_aSamples;    // 非循环 frameCount+1 个,循环 frameCount 个
    bool m_isLooping;
};
  • 真实引擎不会这样存,而是压缩,见 动画压缩。
  • 样本本质上定义了每个关节 10 个标量(或两个向量、一个四元数)的连续通道函数;理论上这些函数在整个片段上光滑连续(相机切镜这类人为设定的不连续除外);很多引擎在样本间线性插值,实际用的是分段线性近似(卷 II 13.4.5)。
  • 元通道 (metachannel):与姿势无关但要与动画同步的数据。最常见的是事件触发通道:局部时间越过触发点时向引擎发事件,例如脚着地时播脚步声和尘土粒子;还有 Maya 定位器 (locator),常用来驱动过场相机(FOV 等放在额外浮点通道),以及纹理滚动、材质参数、灯光参数等(卷 II 13.4.6)。

网格、骨骼与片段的关系

一类角色有一套骨骼、一个或多个网格、一个或多个片段。骨骼是中心:皮肤附着在骨骼上,与片段无关;片段针对某个骨骼,不知道皮肤。新骨骼往往意味着一整套新动画,所以设计上尽量减少骨骼种类,多做蒙到同一骨骼的网格来制造角色多样性(卷 II 13.4.7)。

动画重定向:形态相同的骨骼只需重映射关节索引;不同时更复杂。Naughty Dog 让动画师定义重定向姿势 (retarget pose),记录源骨骼与目标骨骼绑定姿势的本质差异,运行时据此调整源姿势(卷 II 13.4.7.1)。更高级的方法 GEA 推荐 Dutreve 等《Feature Points Based Facial Animation Retargeting》和 Hecker 等《Real-time Motion Retargeting to Highly Varied User-Created Morphologies》(Spore)。UE5 的做法见 IK Rig 与动画重定向。

矩阵约定说明

  • 13.3.2 把 PjP_j 写成 [SjRj0Tj1]\begin{bmatrix}S_jR_j&\mathbf 0\\T_j&1\end{bmatrix}(平移在最下一行),与 13.5.2 的蒙皮公式 vMC=vMBBj→M−1Cj→Mv_M^C=v_M^B B_{j\to M}^{-1}C_{j\to M}(式 13.4)和全局姿势连乘顺序 P5→4P4→3⋯P_{5\to4}P_{4\to3}\cdots 一样,都是行向量左乘的约定,书中前后一致。约定对照见 齐次坐标与矩阵约定。(2026-10-12 复核:此前本页称 13.3.2 为列向量写法、与 13.5.2 不一致,是误读 PDF 文本,已撤回。)
  1. Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
  2. Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 13 章 13.1–13.4 节

相关页面

游戏美术顶点混合与蒙皮Vertex Blending & Skinning顶点混合(也叫线性混合蒙皮、enveloping、骨骼子空间变形)让一个顶点受多根骨骼的变换影响,按权重混合结果,使关节处的"皮肤"连续弯曲。它非常适合在 GPU 上执行;主要缺点是关节折叠、扭转和自相交,可用双四元数蒙皮等方法改善。游戏美术变形动画Morphing变形在两个模型之间插值,需要解决顶点对应和插值两个问题。顶点一一对应时可以逐顶点线性插值;更直观可控的形式是变形目标/混合形状:在中性模型上叠加加权的差分向量,常用于面部动画。过场中无法用这些方法表达的动画,可以用压缩后的几何缓存逐帧回放。游戏开发动画混合Animation Blending动画混合把两个或多个输入姿势合成一个输出姿势。基本工具是对每个关节的局部 SRT 分别做 lerp(旋转用 nlerp 或 slerp);在此之上有时间插值、交叉淡入淡出、方向移动、一维/二维混合空间、部分骨骼混合和叠加混合(差分片段)。前几种都是加权平均,叠加混合则是"加上一段变化"(GEA4 卷 II 13.6)。游戏开发动画压缩Animation Compression未压缩的动画每关节每样本最多 10 个 32 位浮点通道,数据量巨大。GEA 列出的压缩手段按力度递增:省略无用通道、量化(如 16 位 RL 编码)、降低采样率或省略近似线性的关键帧、用 B 样条拟合曲线、小波压缩,以及最根本的:只把需要的片段放进内存(选择性加载与流式加载)(GEA4 卷 II 13.8)。游戏开发动画管线与动作状态机Animation Pipeline & Action State Machines低层动画管线把片段和混合规格变成局部姿势、全局姿势和蒙皮矩阵调色板;其上的动作状态机 (ASM) 给游戏代码提供"按状态驱动动画"的接口。每个状态是任意复杂的片段混合,跟踪当前所有片段的方式有扁平加权平均和混合树两种;过渡用数据驱动的过渡矩阵描述,控制参数通过节点搜索、命名变量或控制结构体暴露给代码(GEA4 卷 II 13.9–13.10)。游戏开发游戏时间线与时钟Game Timelines & Clocks游戏引擎要同时处理多种「时间」:真实时间、游戏时间、动画片段的局部时间、CPU 周期等。GEA 用抽象时间线 (abstract timeline) 统一看待它们,并讨论帧时间 \Delta t 的测量方法、高精度计时器、时间单位与时钟变量类型的取舍,以及断点恢复后的异常 \Delta t 处理。(卷 I 第 8 章 引言、8.4–8.5 节)游戏数学四元数Quaternion单位四元数可以紧凑地表示任意三维旋转,与轴-角表示互相转换很简单,并能做稳定、匀速的朝向插值(slerp),这些都是欧拉角做不好的。它可以高效地转换为矩阵以便与其他变换合并。图形学坐标空间Coordinate Spaces顶点从模型到屏幕要依次经过模型空间、世界空间、观察空间、裁剪空间、标准化设备坐标 (NDC)、窗口坐标。每一步变换都有明确目的,大部分可以用 4×4 矩阵表示并相乘合并。游戏开发 · UE5IK Rig 与动画重定向IK Rig & RetargetingIK Rig 资产为某个骨骼网格定义 IK 目标 (Goal)、求解器栈 (Solver Stack) 和骨骼设置;IK Retargeter 用两个 IK Rig 中定义的重定向链 (retarget chains),在骨骼数量、骨骼名称和朝向都不同的骨架之间传递动画,还可以用 IK 保持手脚接触点的精确。参考姿势不同(例如 T 形与 A 形)时,需要编辑重定向姿势。游戏开发 · UE5Sequencer 过场动画SequencerSequencer 是 UE 的多轨道过场动画编辑器:在 Level Sequence 资产里添加轨道和关键帧,来驱动物体、角色和相机。数据存放在 Level Sequence 资产(内容浏览器中),由关卡里的 Level Sequence Actor 把它绑定到关卡并播放。Camera Cuts 轨道在播放时接管相机;最终的高质量输出通过 Movie Render Queue 完成,可以搭配路径追踪器。游戏开发字符串与唯一标识符Strings & Unique Identifiers字符串在 C/C++ 中只是字符数组,变长意味着要么硬编码长度上限、要么动态分配;比较和复制都是 O(n)。引擎内部大量用字符串做资源名和对象 ID,处理不当会严重拖慢游戏。GEA 的建议:运行时代码尽量避免字符串类,若用则了解其成本并按引用传递;路径类是值得专门做的例外;对象与资产的唯一标识用哈希字符串 ID(string id),兼得字符串的可读性与整数的比较速度。游戏数学齐次坐标与矩阵约定Homogeneous Coordinates & Matrix Conventions实时渲染用 4×4 矩阵和四元素齐次坐标统一表示点和方向:方向向量 w=0,点 w=1。这样线性变换与平移可以合成为仿射变换并连乘。RTR4 采用列向量记法、右手观察坐标系;DirectX 采用行向量记法,书中强调这只是记法差异。游戏开发 · UE5动画蓝图与动画系统Animation Blueprint & Animation SystemUE5 角色动画以动画蓝图 (Animation Blueprint) 为核心:它每帧为骨骼网格体 (Skeletal Mesh) 计算最终姿势。动画蓝图内部用状态机 (State Machine) 组织“何时播什么”,用混合空间 (Blend Space) 按速度、方向等参数连续混合,用蒙太奇 (Animation Montage) 在插槽 (Slot) 中插播攻击、交互等一次性动作,用 Control Rig 做程序化骨骼控制(如贴地)。算出的骨骼姿势最终交给蒙皮 (Skinning) 驱动顶点。游戏开发动画约束与后处理Animation Constraints & Post-Processing片段混合之后、渲染之前,动画系统常常还要修改姿势,这叫动画后处理:程序化动画、逆向运动学 (IK)、布娃娃。另一大类需求是约束:把武器挂在手上(挂接点)、让多个角色对齐演出(参考定位器)、手抓物体(手部 IK)、脚不滑步(根运动提取与脚部 IK),以及注视、掩体、穿越辅助等(GEA4 卷 II 13.7、13.11)。游戏美术游戏动画技术基础Game Animation Technical Foundations《GAME ANIM》第 5 章按基础→中级→高级梳理游戏动画师必须掌握的引擎侧概念:三类动画形态(循环 / 线性 / 过渡)、骨骼导出与数值运算、样条与碰撞移动、FK/IK,以及状态机、参数化混合、局部动画、叠加层、布娃娃,再到全身 IK、Look-At、混合形状与程序化系统。本页只收录书中实际讲到的内容,并与引擎架构页互链。游戏美术技术动画Technical Animation第 8 章「Our Project: Technical Animation」覆盖角色从建模约束、蒙皮、绑定,到命名/目录、引用、导出格式与引擎规则、内存与切片、引擎内事件标签与混合时间、测试关与资产卫生。目标是让动画师少踩导出坑、系统可共享缩放。游戏美术动作捕捉与 Motion MatchingMotion Capture & Motion Matching第 11 章回答「要不要动捕」、光学/惯性/深度/表演捕捉差异、拍摄规划与演员工作,以及后期的重定时、姿势夸张、偏移姿势、循环混合;并专节讲 Motion Matching 的适用边界与第三人称地面移动的 shot list。引擎实现细节见已有页 运动匹配(UE Pose Search);本页保留书中制作向观点。游戏美术2D 与像素动画2D & Pixel Art Animation第 2 版新增的第 14 章回顾 2D 游戏动画简史与选型利弊,对比像素、手绘、转描、模块化/补间等产线,并讲清历史硬件限制(分辨率、调色板、精灵表),再落到软件选型、线稿清理、子像素、帧率与帧数、Hitbox/Hurtbox、背景与视差等实操概念;案例含 Shovel Knight 与 Streets of Rage 4。

被这些页面引用2 篇

输入关键词开始搜索

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