概念页
齐次坐标与矩阵约定
Homogeneous Coordinates & Matrix Conventions
实时渲染用 4×4 矩阵和四元素齐次坐标统一表示点和方向:方向向量 ,点 。这样线性变换与平移可以合成为仿射变换并连乘。RTR4 采用列向量记法、右手观察坐标系;DirectX 采用行向量记法,书中强调这只是记法差异。
为什么需要 4×4 和齐次坐标
- 线性变换满足 与 。缩放、旋转等三元素向量的线性变换都能用 3×3 矩阵表示。
- 平移 不是线性的:作用在两个向量上再相加,会把 加两次。
- 仿射变换先做线性变换再平移,通常存成 4×4 矩阵。平移、旋转、缩放、反射、切变矩阵都是仿射的;仿射变换保持直线的平行性,但不一定保持长度与角度。(RTR4 第 4 章开头)
点与方向
| 实体 | 齐次形式 | 平移矩阵的作用 |
|---|---|---|
| 方向向量 | 不受影响,方向不能被平移 | |
| 点 | 被平移 |
至此介绍的变换都保持 不变、矩阵最后一行为 。透视投影是例外:变换后 通常不为 1,需要齐次化(除以 )得到非齐次点。几何上,齐次化可以理解为把点投影到 平面上。(RTR4 4.7)
点与方向的差别完全由 决定:平移只作用在 的点上。
flowchart TD
In["输入四元向量"] --> W{"w 分量"}
W -->|"w = 1 点"| Pt["经仿射变换:被旋转+缩放+平移"]
W -->|"w = 0 方向"| Dir["经仿射变换:只被线性部分作用,平移项乘 0"]
Pt --> Out1["结果仍为点 w=1"]
Dir --> Out2["结果仍为方向 w=0"]列向量与行向量
- RTR4 用列向量:,平移量在最右一列,复合矩阵 从右往左作用。
- DirectX 等把平移放在最下一行,向量是行向量(书中称 row-major form),矩阵顺序反过来、从左往右读;DirectX 文档中的投影矩阵因此是本书矩阵的转置形式。
- 书中强调这纯粹是记法差异:矩阵存入内存时,16 个值中最后 4 个都是三个平移量加一个 1。(RTR4 4.1.1)
列向量与行向量只是记法镜像:变换顺序对向量「最近的矩阵先作用」这一口诀两边通用。
flowchart LR
subgraph Col["列向量约定 Mp"]
direction TB
C1["p"] --> C2["先 S"]
C2 --> C3["再 R"]
C3 --> C4["再 T"]
C4 --> C5["写作 T R S p"]
end
subgraph Row["行向量约定 pM"]
direction TB
R1["p"] --> R2["先 S"]
R2 --> R3["再 R"]
R3 --> R4["再 T"]
R4 --> R5["写作 p S R T"]
end
Col -.->|"矩阵互为转置"| Row右手与左手坐标系
- 书中假设观察者沿相机的 轴看, 向上、 向右,这是右手系;绕 z 轴的正角度旋转为逆时针(z 轴指出纸面)。
- DirectX 等使用左手系,观察方向为 。两种都正确,最终效果相同。
- 投影后的视口通常是左手系(z 指入屏幕),正交投影矩阵里因此隐含一次镜像。(RTR4 4.7.1)
世界的"上"方向
- 制造业、3D 打印、建筑和 GIS 通常 z 朝上;航空与船舶以 为上;面向媒体的建模系统常以 y 为上,与屏幕的上方向一致。RTR4 默认 y-up。
- 两种约定只差一个 90° 旋转(可能还有一次镜像),但不知道对方用哪种就会出问题。
- 相机观察空间里的"上"与世界的"上"无关:俯瞰地面的相机在 y-up 世界中的上方向是 ,但在观察空间里依然是 y 朝上。(RTR4 4.2.1)
取舍与常见坑
- 在不同 API 或工具间移植时,矩阵记法、手性、上方向三件事都要核对。
- 用右下角元素 也能实现均匀放大 5 倍,但必须再做齐次化,多出除法;若系统总是做除法则没有额外开销。(RTR4 4.1.3)
GEA 的视角:矩阵基础与行向量约定(卷 I 5.3)
GEA 第 5 章从游戏引擎程序员的角度讲同样的内容,但采用行向量约定,与本页上文 RTR4 的列向量约定相反。下面按 GEA 小节整理,并标出与 RTR4 的差异。
矩阵、行列式与矩阵种类(卷 I 5.3、5.3.1–5.3.2)
- 矩阵是 的标量数组,元素记作 (行 r、列 c),便于表示平移、旋转、缩放等变换。
- 原书问题:GEA 开头称矩阵便于表示「平移、旋转、缩放等线性变换」。平移不是线性变换(见本页上文 RTR4 的反例),而是仿射变换;GEA 自己在 5.3.8 也说明 3×3 矩阵无法表示平移、必须借助 4×4 齐次坐标。
- 行列式:;3×3 按第一行展开:。行列式为 0 时矩阵不可逆。
- 正交矩阵 (orthogonal / orthonormal):3×3 的行、列都是两两正交的单位向量;再加 即特殊正交矩阵,表示纯旋转。
- 仿射矩阵:保持直线平行性与距离比例、不一定保持绝对长度和角度的 4×4 变换矩阵,是旋转、平移、缩放、切变的任意组合。
乘法、单位阵、逆与转置(卷 I 5.3.3、5.3.5–5.3.7)
- 的元素是 的行与 的列的点积,要求内维相等。两个变换矩阵之积同时执行两个变换,因此可预先合并一长串变换再批量作用于大量向量;矩阵乘法因此也叫串接 (concatenation)。不满足交换律:。
- 单位阵 :。
- 逆:。并非所有矩阵可逆,但所有仿射矩阵都可逆;一般用高斯消元或 LU 分解求逆。
- 原书问题:「所有仿射矩阵(旋转、平移、缩放、切变的组合)都可逆」不严格:含零缩放(某轴缩放因子为 0,把物体压成平面或点)的仿射矩阵行列式为 0,不可逆。仿射变换可逆当且仅当其左上 3×3 线性部分可逆()——这正是 GEA 5.3.1 自己给出的行列式判据。。
- 转置:行列互换,。正交(纯旋转)矩阵的逆就是转置,远比一般求逆便宜;在行向量库与列向量库之间搬数据时,矩阵也要互相转置。
行向量还是列向量(卷 I 5.3.4)
- 行向量 必须写在矩阵左边:;列向量写在右边:。
- 多个变换 A、B、C 依次作用:行向量 从左往右读;列向量 从右往左读。记法口诀:离向量最近的矩阵最先作用。
- GEA 选择行向量,理由是从左到右的变换顺序对英语读者最直观;并提醒读者核对所用引擎、书籍和网页的约定——向量写在矩阵左边是行向量,右边是列向量;用列向量时要把书中所有矩阵转置。
- 与 RTR4 的对照:RTR4 用列向量( 从右往左),GEA 用行向量( 从左往右),两书矩阵互为转置;两书都强调这只是记法。
齐次坐标与方向向量(卷 I 5.3.8)
- 引子:2×2 矩阵可表示二维旋转(正角度为逆时针),行向量写法 ;它其实就是绕 z 轴的三维旋转,扩成 3×3 即可。三维旋转能用 3×3 表示,平移却不能。
- 3×3 矩阵无法表示平移:无论怎样排列 的分量,乘法都得不到 这样的和。改用 4×4、把 放在最下一行(行向量约定)、向量第四分量 ,第一列点积即为 ;右下角为 1、第四列其余为 0,结果的 仍为 1。点在齐次坐标中总有 ;游戏引擎的大部分 3D 矩阵运算都用 4×4 矩阵与齐次四元素向量。(原书此处一句话说「与列向量 r 相乘」,与上下文的行向量写法不一致,属笔误。)
- 方向向量 ,与矩阵相乘时 消去平移:。平移方向向量会改变其大小,通常不是想要的。
- 齐次到三维:。 时除法无影响;方向除以 得无穷,纯方向向量就像四维齐次空间中的无穷远点——能旋转、不能平移。
4×3 矩阵(卷 I 5.3.10)
仿射 4×4 矩阵(行向量约定下)最右一列恒为 ,游戏程序员常省去这一列以节省内存,数学库中常见 4×3 仿射矩阵。
矩阵在内存中的存储(卷 I 5.3.14)
- C/C++ 二维数组
float m[4][4]第一个下标是行、第二个是列,列下标在内存中变化最快。 - 两种布局:(1) 把基向量 各放一行,连续存储;(2) 各放一列,跨步存储。
- 布局 (1) 可以直接把一行当作 4 元素向量取出,并与行向量公式一致;布局 (2) 有时用于 SIMD 下的快速矩阵-向量乘法(见 SIMD 向量化)。作者遇到的多数引擎用布局 (1)。
- 快速判断法:调用库函数构造平移 (4, 3, 2),若第 3 行(从 0 数)为
4.0f, 3.0f, 2.0f, 1.0f,则向量存于行,否则存于列。这与 RTR4「内存中最后 4 个值都是三个平移量加 1」的说法一致。
PBRT 的视角:列向量、行主序存储与随身携带的逆矩阵(PBRT 4e 3.9.1–3.9.3、3.10)
- 记法:PBRT 与 RTR4 一样用列向量 ;矩阵的各列就是原坐标系的基向量和原点变换后的位置()。下标从 0 开始,与代码对应。复合 表示先 后 。PBRT 的"延伸阅读"特别提醒:Rogers & Adams 等经典教材用行向量 ,矩阵要转置——与 GEA 的行向量约定(上文)是同一个差别。
- 同一矩阵的两种解读:"在同一标架内移动点"和"把坐标从一个标架换到另一个",两者不兼容;pbrt 的大部分用法是后者。
- 齐次坐标只藏在变换实现里:pbrt 没有齐次点类,变换函数内部隐式补 (点)或 (向量),只有 (第 5 章的投影变换)时才做除法。 与 是同一个点。
- 存储:
SquareMatrix<4>按行主序存(m[i][j]是第 行第 列)——内存布局与列向量记法是两回事,不要混淆。Transform同时存矩阵和逆矩阵,单精度下共 128 字节;几百万个形状往往只有几千个不同变换,所以形状只存指针,场景构建时用InternCache去重。求逆失败时逆矩阵填 NaN,只要不调用用到逆的方法仍可使用;能写出解析逆的变换(平移、缩放、旋转)都直接传入逆矩阵,避免通用 4×4 求逆的开销和精度损失。,所以复合变换的逆就是t2.mInv * mInv。
| 约定 | RTR4 | GEA4 | PBRT 4e |
|---|---|---|---|
| 向量写法 | 列向量 | 行向量 | 列向量 |
| 手性 | 右手,看 | 左手,看 | 左手,看 |
| 逆矩阵 | 按需计算,优先用特殊结构求逆 | 正交矩阵的逆即转置 | 每个 Transform 都随身存逆 |
原书小问题(PBRT 第 3 章参考文献):RTR4 的作者之一写成 "A. Peesce",应为 A. Pesce(Angelo Pesce)。来源:https://pbr-book.org/4ed/Geometry_and_Transformations/Further_Reading 与 RTR4 封面署名(Akenine-Möller, Haines, Hoffman, Pesce, Iwanicki, Hillaire)。
出处
- realtime_rendering_4ed.pdf 第 4 章 Transforms
- Game_Engine_Architecture_4Ed_-_Jason_Gregory.pdf
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 I 第 5 章 5.3 节(5.3.1–5.3.8、5.3.10、5.3.14)
- PBRT 4e source excerpt: chapter 03 (Geometry and Transformations)
- Pharr, Jakob, Humphreys《Physically Based Rendering: From Theory to Implementation》第 4 版(MIT Press, 2023)第 3 章 3.9–3.10 节,pbr-book.org/4ed/Geometry_and_Transformations
相关页面
游戏数学基本仿射变换Basic Affine Transforms平移、旋转、缩放、切变是摆放和变形物体的基础矩阵;它们的连乘顺序有关、但满足结合律。刚体变换的逆可以直接写出,法线要用伴随矩阵的转置(传统说法是逆转置)变换。理解这些矩阵的性质能写出更快、更正确的变换代码。游戏数学投影矩阵Projection Matrix投影矩阵把视景体变换到规范视体(OpenGL 为 [-1,1]^3,DirectX 的 z 为 [0,1]),在那里裁剪更高效。正交投影保持平行线平行、物体大小与距离无关;透视投影让远处变小,产生的深度与观察深度成反比,近平面位置和"反向 z"决定深度精度。图形学坐标空间Coordinate Spaces顶点从模型到屏幕要依次经过模型空间、世界空间、观察空间、裁剪空间、标准化设备坐标 (NDC)、窗口坐标。每一步变换都有明确目的,大部分可以用 4×4 矩阵表示并相乘合并。游戏数学视锥相交测试View Frustum Intersection Tests层次视锥剔除遍历 BVH 时最频繁调用的就是视锥与包围体的测试,理想结果分三态:完全在外(剪掉子树)、完全在内(子树免测)、相交(递归)。本页讲从组合矩阵直接提取六个视锥平面、把"BV 对视锥"转化为"点对扩张/收缩体积"的推导思路,以及视锥-球、视锥-盒的高效保守测试及其误报情况。游戏数学直线与平面求交Line & Plane Intersections本页收录 RTR4 第 22.15~22.16 节的基础几何工具:二维直线/光线/线段求交(垂直点积法与无除法的早期拒绝法)、三维直线求交与异面直线最近点,以及三个平面的交点公式(可用于求 k-DOP 等平面围成凸体的角点)。这些在游戏中常用于射线检测、二维几何、碰撞与包围体构建。图形学实时渲染Real-Time Rendering实时渲染是在计算机上快速生成图像、并让图像随用户输入即时变化的技术。RTR4 认为它由三个要素共同定义:交互性、三维空间感,以及图形加速硬件 (GPU)。游戏数学欧拉角与万向节锁Euler Angles & Gimbal Lock欧拉变换用 head(yaw)、pitch、roll 三个角度构造朝向矩阵,直观、易于用日常语言讨论,适合小角度调整和观察者朝向。但它依赖旋转顺序,两组欧拉角难以组合和插值,并且会出现万向节锁,因此更复杂的朝向处理需要四元数。游戏开发SIMD 向量化SIMD VectorizationSIMD(单指令多数据)用一条机器指令并行处理多个数据。x86 上从 MMX 发展到 SSE(128 位,4 个 float)、AVX(256 位,8 个)和 AVX-512(512 位,16 个)。GEA 用 SSE 内建函数演示:数组相加、点积、向量×矩阵、矩阵×矩阵,强调两点——避免寄存器内的水平相加(先转置数据),以及把 SIMD 寄存器看成 N 条并行的「通道 (lane)」而不只是一个 4D 向量;条件分支则用向量谓词化 (vector predication / select) 代替。游戏数学点与向量运算Points & Vector Operations游戏程序员最常用的数学是三维向量与矩阵(三维线性代数)。本页按 GEA 第 5 章整理点与向量的基础:坐标系与手性、点与方向的区别、标量乘与 Hadamard 积、加减、模长与归一化、点积与投影、叉积、伪向量与外代数,以及线性插值 (lerp)。贯穿全章的两条经验是:能在二维里想清楚的问题先在二维里想,以及能不开方就不开方。游戏数学旋转表示的比较Comparison of Rotational Representations旋转可以用欧拉角、3×3 矩阵、轴角、四元数表示,再加上平移与缩放就有 4×4(或 4×3)矩阵与 SRT(SQT)变换;更进一步还有对偶四元数。没有一种在所有场合都最好。GEA 按大小、直观性、能否直接作用于向量、能否插值、有无万向节锁比较它们,并用「参数个数 − 约束个数 = 3 个自由度」统一解释为什么它们用的浮点数不同。图形学可编程着色器与 GPU 管线Programmable Shaders & GPU PipelineGPU 把第 2 章的概念管线实现为一组硬件阶段,分为完全可编程、可配置但不可编程、完全固定三类。现代 GPU 采用统一着色器架构:各类着色器共用同一套编程模型和核心,由 GPU 自行分配负载。着色器用 HLSL、GLSL 等类 C 语言编写,输入分为 uniform 和 varying 两类。游戏美术顶点混合与蒙皮Vertex Blending & Skinning顶点混合(也叫线性混合蒙皮、enveloping、骨骼子空间变形)让一个顶点受多根骨骼的变换影响,按权重混合结果,使关节处的"皮肤"连续弯曲。它非常适合在 GPU 上执行;主要缺点是关节折叠、扭转和自相交,可用双四元数蒙皮等方法改善。游戏开发骨骼、姿势与动画片段Skeletons, Poses & Animation Clips角色动画系统的数据核心是三样东西:骨骼(关节层级)、姿势(每个关节的 SRT 变换)和动画片段(姿势随局部时间变化的采样)。GEA 把各种动画方法看成对"逐点控制表面"这一理想的不同压缩方式;骨骼蒙皮用少量关节驱动大量顶点,是今天最主流的方案(GEA4 卷 II 13.1–13.4)。游戏数学马尔可夫链与状态机概率Markov Chains & State-Machine Probability当一个随机过程可能无限进行下去(如"每次 80% 再加 1 点伤害")时,无法枚举所有结果;把它画成以概率转移的状态机,写成转移矩阵,再用列向量反复左乘矩阵(马尔可夫链 (Markov Chain)),就能得到任意回合后的状态分布、稳态、游戏时长的中位数/均值/众数;反向则可用递归把复杂局面化归为已知的简单局面。本页按 Schreiber 与 Romero 第 22 章整理(p.525–556),并核对了书中数字。