平移、旋转、缩放、切变是摆放和变形物体的基础矩阵;它们的连乘顺序有关、但满足结合律。刚体变换的逆可以直接写出,法线要用伴随矩阵的转置(传统说法是逆转置)变换。理解这些矩阵的性质能写出更快、更正确的变换代码。
基本矩阵速查
| 变换 | 记号 | 逆 | 性质 |
|---|
| 平移 | T(t) | T(−t) | 仿射;方向向量不受影响 |
| 旋转 | Rx(ϕ) 等 | RT,或 Ri(−ϕ) | 正交、行列式为 1、刚体 |
| 缩放 | S(s) | S(1/sx,1/sy,1/sz) | 均匀/非均匀(各向同性/异性) |
| 切变 | Hij(s) | Hij(−s) | 行列式为 1,保体积 |
Rz(ϕ)=cosϕsinϕ00−sinϕcosϕ0000100001
- 任意 3×3 旋转矩阵(转角 ϕ)的迹与轴无关:tr(R)=1+2cosϕ。
- 旋转会保持旋转轴上的点不动;刚体变换保持点间距离和手性。
- 切变 Hxz(s) 把点变成 (px+spz, py, pz);第一个下标是被改变的坐标,第二个是起作用的坐标。书中提到游戏里可用切变扭曲整个场景做迷幻效果。
复合操作的模式:"移过去—变换—移回来"
绕任意点旋转、沿任意正交基缩放,都遵循「移到原点 → 做变换 → 移回去」的同一模式。
flowchart LR
P["点在枢轴 p 处"] --> T1["平移 T(-p):移到原点"]
T1 --> X["在原点做 R 或 S"]
X --> T2["平移 T(p):移回"]
T2 --> Out["复合 X = T(p) · Op · T(-p)"]
- 绕点 p 旋转:X=T(p)Rz(ϕ)T(−p)。
- 沿正交基 fx,fy,fz 缩放:X=FS(s)FT。
- 绕任意单位轴 r 旋转:构造正交基 (r,s,t)——取 r 绝对值最小的分量置 0、交换另外两个并取反其一得到 sˉ,归一化后 t=r×s;以它们为行组成 M,则 X=MTRx(α)M。也可以直接用 Goldman 给出的闭式矩阵。(RTR4 4.2.4)
反射(镜像)
- 缩放因子中有一个或三个为负时得到反射矩阵;只有两个为 −1 等价于旋转 π。旋转与反射相乘仍是反射。
- 反射会把逆时针顶点顺序变成顺时针,导致光照和背面剔除出错,需要特殊处理。
- 检测:左上 3×3 的行列式为负即为反射。
连乘顺序
- 矩阵乘法不可交换:书中例子 S(2,0.5,1) 与 Rz(π/6) 两种顺序结果截然不同。
- 合并矩阵是为了效率:几百万顶点都要缩放、旋转、平移时,先合并成 C=TRS 再逐顶点乘一次。S 最先作用所以写在最右;TRS 也是场景图常用顺序。
本地到世界常用 TRS(列向量下右乘):缩放最先、平移最后;求逆则参数取反并逆序相乘。
flowchart TD
Local["本地坐标 p"] --> S["缩放 S"]
S --> R["旋转 R"]
R --> T["平移 T"]
T --> World["世界坐标:C = T R S"]
World --> Inv["求逆:C⁻¹ = S⁻¹ R⁻¹ T⁻¹"]
- 乘法满足结合律,例如可以先算好刚体部分 TR,再与 Sp 相乘。
刚体变换与 lookAt
X=T(t)R 的逆:
X−1=RTT(−t)
即旋转部分转置、平移取负,并以相反顺序相乘;写成分块形式时平移列为 −RˉTt。
相机朝向(gluLookAt 的做法):相机在 c、看向 l、给定大致向上 u′:
- v=(c−l)/∥c−l∥,r=−(v×u′)/∥v×u′∥,u=v×r;
- 观察矩阵先平移 −t(相机位置移到原点),再用以 r,u,v 为行的矩阵换基,平移列为 (−t⋅r,−t⋅u,−t⋅v)。
法线变换
- 同一矩阵能正确变换点、线、三角形和切线,但不能总是正确变换法线:例如沿 x 缩放 0.5 后,直接变换的法线不再垂直于表面。
- 正确方法是用矩阵伴随矩阵的转置;传统说法是逆的转置。伴随矩阵总存在,而逆矩阵在行列式为 0 时不存在。变换后法线一般需要重新归一化。
- 平移不影响法线,常见的模型变换是仿射的,所以只需计算左上 3×3 的伴随矩阵。
- 若只由平移、旋转、均匀缩放组成,可以直接用原矩阵变换法线;只有平移和旋转时长度不变无需归一化;已知均匀缩放因子(如放大 5.2 倍)时,除以该因子即可,或预先把 3×3 部分除以该因子。
- 切线与法线性质不同,总是直接用原矩阵变换。(RTR4 4.1.7)
切向与点一样用原矩阵 M;法线要保持与切向垂直,必须用 (M−1)T(或伴随转置)。
flowchart LR
T0["切向 t"] --> Mt["t' = M t"]
N0["法线 n"] --> Mn["n' = (M⁻¹)ᵀ n"]
Mt --> Orth["要求 n' · t' = 0"]
Mn --> Orth
求逆的选择(RTR4 4.1.8)
| 已知信息 | 方法 |
|---|
| 由已知参数的简单变换组成 | "反转参数和顺序",如 M=T(t)R(ϕ) 时 M−1=R(−ϕ)T(−t);能保持精度,这在渲染超大世界时很重要 |
| 正交矩阵 | 转置即逆 |
| 一无所知 | 伴随矩阵、克莱姆法则、LU 分解或高斯消元;前两者分支更少,更适合现代硬件 |
若逆矩阵只用来变换向量,通常只需求左上 3×3 部分的逆。
矩阵分解(RTR4 4.2.3)
只拿到一个合成矩阵时,可能需要:提取缩放因子、判断是否只有刚体变换、在只有矩阵的关键帧之间插值、去除旋转矩阵中的切变等。平移直接取最后一列;行列式为负说明有反射;分离旋转、缩放、切变需要专门算法(Thomas、Goldman、Shoemake)。
GEA 的视角:行向量形式的基本变换矩阵(卷 I 5.3.9、5.3.13)
GEA 用行向量约定(r′=rM,平移在最下一行),所以下列矩阵是上文 RTR4 列向量矩阵的转置;约定对照见 齐次坐标与矩阵约定。
分块形式
任何仿射 4×4 矩阵都可以由纯平移、纯旋转、纯缩放(和很少用的切变)串接而成,并分为四块:
Maffine=[U3×3t1×303×11],[r 1]Maffine=[rU+t 1]
U 表示旋转和/或缩放,t 是平移。GEA 省略切变,理由是游戏中很少用。
平移、旋转、缩放(行向量形式)
- 平移:[It01],求逆只需把 t 取负。
- 旋转:[R001],角度用弧度。按行向量约定,三个 3×3 旋转块为
\mathbf{R}_y(\theta)=\begin{bmatrix}\cos\theta&0&-\sin\theta\\0&1&0\\\sin\theta&0&\cos\theta\end{bmatrix},\
\mathbf{R}_z(\gamma)=\begin{bmatrix}\cos\gamma&\sin\gamma&0\\-\sin\gamma&\cos\gamma&0\\0&0&1\end{bmatrix}$$
(PDF 抽取文本中矩阵排版错乱;$\mathbf{R}_y$ 第一行与 $\mathbf{R}_z$ 由原文直接可读,并与 GEA 5.3.12.2 换基例子 $\mathbf{i}_C=(\cos\gamma,\sin\gamma,0)$、$\mathbf{j}_C=(-\sin\gamma,\cos\gamma,0)$ 吻合;$\mathbf{R}_x$ 由原文「y 转向 z 为正」及与 $\mathbf{R}_z$ 同形的说明确定。)
- GEA 的观察:3×3 块里的 1 总在旋转轴上;正旋转为 x→y(绕 z)、y→z(绕 x)、z→x(绕 y),z→x「绕回来」,所以 $\mathbf{R}_y$ 相对另两个是转置的(叉积视角见 [[点与向量运算 (Points & Vector Operations)]]);纯旋转的逆就是转置,因为 $\cos(-\theta)=\cos\theta$、$\sin(-\theta)=-\sin\theta$,取负角只让两个正弦项互换位置。
- **缩放**:$\mathbf{r}\mathbf{S}=[s_xr_x\ s_yr_y\ s_zr_z\ 1]$,求逆用倒数 $1/s_x,1/s_y,1/s_z$。
- **均匀缩放**下球仍是球,非均匀缩放会把球变成椭球;为了让包围球检测简单快速,**许多引擎规定可渲染几何和碰撞图元只允许均匀缩放**。
- 均匀缩放矩阵 $\mathbf{S}_u$ 与旋转可交换:$\mathbf{S}_u\mathbf{R}=\mathbf{R}\mathbf{S}_u$——**只对均匀缩放成立**。
### 法线变换(卷 I 5.3.13)
- 法向量除(通常)单位长度外,还要求始终垂直于其表面。若点和普通向量用 3×3 矩阵 $\mathbf{M}_{A\to B}$ 变换,法线要用 $(\mathbf{M}_{A\to B}^{-1})^T$。
- 只含均匀缩放、无切变时,角度保持不变,原矩阵对法线也适用;含非均匀缩放或切变时角度不再保持,需要逆转置把法线「拉回」垂直。
- GEA 开头说变换法线时要同时保持其**长度**与垂直性,但逆转置只保证垂直性:含缩放时(包括均匀缩放)结果一般不再是单位长度,需要变换后**重新归一化**。GEA 的推导参考为 Lengyel [36] 3.5 节与 [34] 3.2 节。
- GEA 给出的另一种解释:**表面法线本质上是伪向量**而非普通向量(见 [[点与向量运算 (Points & Vector Operations)]])。
- **与 RTR4 的对照**:上文 RTR4 主张用伴随矩阵的转置(总存在,逆矩阵在行列式为 0 时不存在),并把「逆转置」称作传统说法;GEA 只给出逆转置,未讨论伴随矩阵。平面四元向量同样可以用逆转置变换,见 [[几何图元的表示 (Geometric Primitive Representations)]]。
## PBRT 的视角:旋转构造、法线与手性(PBRT 4e 3.9.4–3.10.8)
### 基本变换的性质(3.9.4–3.9.6)
平移 $T(\Delta x,\Delta y,\Delta z)$ 只影响点(向量的 $w=0$),满足 $T(0,0,0)=I$、可交换、$T^{-1}(x,y,z)=T(-x,-y,-z)$;缩放 $S^{-1}(x,y,z)=S(1/x,1/y,1/z)$;同轴旋转可交换、$R_a^{-1}(\theta)=R_a(-\theta)=R_a^T(\theta)$。PBRT 把 $R_x(\theta)$(第二行 $\cos\theta,-\sin\theta$,第三行 $\sin\theta,\cos\theta$)称为**左手系下的顺时针旋转**,矩阵本身与 RTR4 右手系下称为"逆时针"的那个相同——叫法取决于手性和观察方向,数字没有变。`HasScale()` 通过变换三根坐标轴、看长度是否明显偏离 1 来判断有没有缩放。
### 绕任意轴旋转(3.9.7)
设单位轴 $a$、待转向量 $v$:$v_c=a(v\cdot a)$,$v_1=v-v_c$,$v_2=v_1\times a$,则 $v'=v_c+v_1\cos\theta+v_2\sin\theta$;把它作用于三根坐标轴就得到矩阵各行,逆仍是转置。pbrt 另有直接接收 $\sin\theta,\cos\theta$ 的版本,省去重复的三角函数。
### 把一个向量转到另一个:两次 Householder 反射(3.9.8)
用 $\arccos$ 求角、叉积求轴的做法在两向量接近平行时不稳定,还要多次三角函数。`RotateFromTo(f,t)` 改用两次反射:Householder 矩阵 $H(v)=I-\frac{2}{v\cdot v}vv^T$ 把 $v$ 变为 $-v$、保持与 $v$ 正交的向量不变,$R=H(r-t)\,H(r-f)$(式 3.10)先把 $f$ 反射到中间向量 $r$,再把 $r$ 反射到 $t$。$r$ 取某根坐标轴,要求 $f$ 和 $t$ 在该轴上的分量绝对值都小于 0.72:0.72 略大于 $\sqrt2/2$,单位向量至多有一个分量的绝对值 $\ge0.72$,所以三根轴里一定能找到一根可用。展开后($u=r-f$、$v=r-t$)
$$r_{ij}=\delta_{ij}-\frac{2}{u\cdot u}u_iu_j-\frac{2}{v\cdot v}v_iv_j+\frac{4(u\cdot v)}{(u\cdot u)(v\cdot v)}v_iu_j$$
本页对随机单位向量验算:$Rf=t$ 的误差约 $10^{-16}$,$\det R=1$(两次反射合成纯旋转)。方法来自 Möller & Hughes (1999),中间向量的选法后由 Hughes (2021) 调整。四元数版本的向量对齐见 [[四元数 (Quaternion)]]。
### Look-at(3.9.9)与 RTR4 的对照
pbrt 的 `LookAt(pos, look, up)` 直接按"矩阵各列 = 相机基在世界中的像"填出 **worldFromCamera**:第四列是相机位置,第三列 $dir=\mathrm{normalize}(look-pos)$(左手系相机看 $+z$),第一列 $right=\mathrm{normalize}(\mathrm{normalize}(up)\times dir)$,第二列 $newUp=dir\times right$;最后求逆得到 cameraFromWorld,两者一起存入 `Transform`。上文 RTR4 的 gluLookAt 做法是右手系:$\mathbf v=(\mathbf c-\mathbf l)/\|\cdot\|$ 指向相机**后方**,并直接写出观察矩阵(旋转转置 + 平移 $-\mathbf t\cdot$各基),不需要通用求逆。两种写法得到的都是正交标架,差别在手性和"先建相机到世界、再求逆"还是"直接写世界到相机"。
### 法线:逆转置还是伴随转置(3.10.3)
由 $n^Tt=0$、$t'=Mt$、$n'=Sn$ 得 $(Sn)^TMt=n^TS^TMt=0$,取 $S^TM=I$ 即 $S=(M^{-1})^T$。pbrt 不显式转置,而是按不同顺序索引已存的逆矩阵,这也是 `Transform` 要随身带逆的原因之一。
| | RTR4(上文) | PBRT 4e |
|---|---|---|
| 推荐公式 | 伴随矩阵的转置,奇异矩阵也存在 | 逆矩阵的转置 |
| 奇异矩阵 | 仍能给出法线方向 | 逆矩阵是 NaN,变换出的法线也是 NaN |
| 代价 | 需另算 3×3 伴随 | 逆矩阵已存,只是换个索引顺序 |
两者对可逆矩阵只差一个标量因子 $\det M$,归一化后方向相同($\det M<0$ 时还差一个符号,见下面的手性讨论)。
### 光线、包围盒和复合(3.10.4–3.10.6)
- 光线:变换原点和方向,另外把原点挪到误差界边缘并相应调整 `tMax`(6.8.6 节)。
- AABB:最简单的做法是变换 8 个角再取包围盒;习题指出利用"8 个角 = 1 个角 + 3 根轴向基向量的线性组合"可以更快(Arvo 1990)。
### 手性翻转与法线朝向(3.10.7、3.11.1)
变换左上 3×3 子矩阵的行列式为负时手性翻转。pbrt 用 $n=\partial p/\partial u\times\partial p/\partial v$ 算法线,而 $S(1,1,-1)\frac{\partial p}{\partial u}\times S(1,1,-1)\frac{\partial p}{\partial v}=S(-1,-1,1)\,n\ne S(1,1,-1)\,n$,叉积算不出这种翻转,所以表面交互要同时根据 `ReverseOrientation` 标志和变换是否翻转手性来决定是否翻转法线。法线朝向对 pbrt 很重要:面光源默认只从法线一侧发光。这与 [[点与向量运算 (Points & Vector Operations)]] 中 GEA "伪向量在反射下要反向"的说法是同一件事。
### 向量标架 Frame(3.10.8)
BSDF 在法线对齐 $z$ 轴的局部坐标中计算。`Frame` 只存三根正交单位向量(3×3,逆就是转置):`ToLocal(v)` 是三个点积;正交矩阵的逆转置就是它自己,所以法线和向量一样变换。
## 相关
- [[齐次坐标与矩阵约定 (Homogeneous Coordinates & Matrix Conventions)]]
- [[欧拉角与万向节锁 (Euler Angles & Gimbal Lock)]]
- [[四元数 (Quaternion)]]
- [[坐标空间 (Coordinate Spaces)]]
- [[顶点着色器 (Vertex Shader)]]
- [[公告板 (Billboarding)]]
- [[法线贴图与凹凸贴图 (Normal & Bump Mapping)]]
- [[顶点混合与蒙皮 (Vertex Blending & Skinning)]]
- [[几何图元的表示 (Geometric Primitive Representations)]]
- [[点与向量运算 (Points & Vector Operations)]]
- [[旋转表示的比较 (Comparison of Rotational Representations)]]
- [[可编程着色器与 GPU 管线 (Programmable Shaders & GPU Pipeline)]]
- [[着色器二维矩阵变换 (2D Matrix Transforms in Shaders)]]