齐次坐标
常见的二维仿射变换包括缩放、旋转和平移。缩放和旋转可以写成 2×2 矩阵,平移需要额外加一个向量,两者无法合并成同一次矩阵乘法;齐次坐标在普通坐标后补一个分量,把平移也写进矩阵。二维点记作 (x,y,1)T,二维向量记作 (x,y,0)T,齐次坐标 (x,y,w)T 与 (kx,ky,kw)T 表示同一个位置,其中 k=0;计算结束后除以 w,得到普通笛卡尔坐标。
二维平移、缩放和旋转分别写成
T(tx,ty)S(sx,sy)R(θ)=100010txty1=sx000sy0001=cosθsinθ0−sinθcosθ0001
其中 R(θ) 表示逆时针旋转 θ。平移量放在第三列:点的 w=1,平移会改变点的位置;向量的 w=0,平移不改变向量。两个点相加得到 w=2,除以 w 后是中点;点减点得到 w=0,结果是向量。
多个变换按矩阵乘法组合。p′=TRSp 表示先缩放、再旋转、再平移;矩阵乘法从右往左作用,交换顺序会得到不同的结果。三维情形使用 4×4 矩阵,点记作 (x,y,z,1)T,向量记作 (x,y,z,0)T,平移量位于第四列,旋转是左上角的 3×3 块。透视投影会用到 w=1 的齐次坐标:投影矩阵把 w 写成视深的函数,除法把远处点的横向坐标压小。
三维旋转
绕单位轴 n^ 旋转角度 θ 的变换可以用一个矩阵表示,这个矩阵称为 Rodrigues 旋转矩阵。把向量 v 分解为平行于轴的分量 v∥ 和垂直于轴的分量 v⊥:
v∥=(n^⋅v)n^,v⊥=v−v∥
旋转时 v∥ 保持不变,v⊥ 在垂直于 n^ 的平面内转动。转动后的垂直分量为
v⊥′=cosθv⊥+sinθ(n^×v)
其中 n^×v=n^×v⊥,它的长度等于 ∣v⊥∣,方向由右手定则确定。把两个分量相加,得到
v′=v∥+cosθv⊥+sinθ(n^×v)
代入 v∥=(n^⋅v)n^=n^n^Tv 和 v⊥=(I−n^n^T)v,整理成矩阵形式:
v′=(cosθI+(1−cosθ)n^n^T+sinθ[n^]×)v
其中 [n^]× 是叉乘对应的反对称矩阵:
[n^]×=0n^z−n^y−n^z0n^xn^y−n^x0
它满足 [n^]×v=n^×v。于是
R(n^,θ)=cosθI+(1−cosθ)n^n^T+sinθ[n^]×
取 n^=(0,0,1) 时,R 退化为二维旋转矩阵的 3×3 形式;取 θ=0 时,R=I。
视图变换
视图变换把世界坐标中的点变换到相机坐标,使相机位于原点、看向 −Z、上方向为 +Y。相机由位置 e、看向方向 g、上方向 t 确定。
直接写世界坐标到相机坐标的矩阵并不方便,平移和三个轴的旋转混在一起,矩阵元素不容易直接看出。相机坐标到世界坐标的矩阵可以直接由相机的位置和三个轴写出;先写这个方向的矩阵,再求逆,就得到视图变换。
相机基向量
相机坐标系的三个轴在世界坐标中表示为
w^=−∣g∣g,u^=∣g×t∣g×t,v^=w^×u^
w^ 指向相机后方,因为相机看向 −Z;u^ 指向相机右方;v^ 指向相机上方。u^ 由 g×t 得到,因此 u^ 与 g 垂直;v^ 再由 w^×u^ 得到,三个轴构成右手正交基。当 g 与 t 平行时,g×t=0,相机姿态退化,需要换一个上方向。
先写相机到世界
相机坐标中的点 (xc,yc,zc) 在世界坐标中表示为
p=e+xcu^+ycv^+zcw^
写成齐次矩阵:
Mc2w=u^xu^yu^z0v^xv^yv^z0w^xw^yw^z0exeyez1
矩阵的前三列是相机三个轴在世界坐标中的方向,第四列是相机位置。
求逆得到视图矩阵
视图变换需要反方向的矩阵,对 Mc2w 求逆。三个轴两两垂直且长度为 1,所以 R=[u^ v^ w^] 是正交矩阵,满足 RTR=I,因此 R−1=RT。对分块矩阵
[R0e1]−1=[RT0−RTe1]
得到
Mview=u^xv^xw^x0u^yv^yw^y0u^zv^zw^z0−u^⋅e−v^⋅e−w^⋅e1
这个矩阵等价于先用 T(−e) 把相机移到原点,再用 RT 旋转坐标轴。平移项是 −u^⋅e 这样的点积,不能直接把 e 的分量取负。
验证
把相机位置 e 代入,得到 (0,0,0)T。把 e+g 代入,旋转部分得到 −w^=(0,0,−1)T,说明视线方向映射到相机坐标的 −Z;把 e+t 代入,若 t 与 g 垂直,结果为 (0,1,0)T,说明上方向映射到 +Y。
正交投影
投影变换把相机空间中的可视区域映射到归一化设备坐标(NDC),NDC 的范围是 [−1,1]3。正交投影的视锥体是长方体,平行线投影后仍然平行,物体的大小不随距离改变;透视投影的视锥体是棱锥台,平行线在投影后可能相交,远处的物体看起来更小。棱锥台是棱锥被平行于底面的平面截去顶部后剩下的部分。
相机看向 −Z,近平面位于 z=−n,远平面位于 z=−f,其中 n,f>0 且 f>n。长方体的左右、下上边界分别为 l,r,b,t,因此 x∈[l,r],y∈[b,t],z∈[−f,−n]。
正交投影分两步:先把长方体中心平移到原点,再沿三个轴缩放到 [−1,1]。中心为
c=(2l+r,2b+t,−2n+f)
平移矩阵为 T(−c),缩放因子为
sxsysz=r−l2=t−b2=n−f2
sz 的分母 n−f 是负数,因此 z 轴在映射时翻转。组合得到
Mortho=r−l20000t−b20000n−f20−r−lr+l−t−bt+bn−fn+f1
代入 x=r 得到 1,代入 x=l 得到 −1;代入 z=−n 得到 −1,代入 z=−f 得到 1。近平面映射到 −1,远平面映射到 +1,这个约定会沿用到透视投影。
透视投影
透视投影的视锥体是一个棱锥台。近平面位于 z=−n,远平面位于 z=−f,近平面是 x,y∈[−n,n] 的正方形,对应 90∘ 的视场角。视场角是相机在垂直方向上能看到的张角;视锥体内的点沿穿过相机的射线投影到近平面,近平面上的点保持不动,远平面上的点被缩放到近平面的大小。
目标是把视锥体映射到 [−1,1]3,近平面映射到 z=−1,远平面映射到 z=+1。整个过程分成两步:先把视锥体挤压成长方体,近平面和远平面的 z 坐标保持不变;再用正交矩阵把长方体映射到 [−1,1]3。
第一步:挤压视锥体
设视锥体内一点为 (x,y,z),其中 z<0。穿过该点和相机的射线与近平面交于
xpyp=−znx=−zny
图中 z 标为正距离;本文的相机坐标中 z<0,所以分母写成 −z。挤压把点映射到 (xp,yp,zsq):横向坐标乘以 n/(−z),纵向坐标同理;zsq 只要求近平面和远平面上的 z 坐标保持不变。
用齐次坐标表示,令 w=−z。w 是正数,远处的点 w 更大,除以 w 后横向坐标更小。挤压矩阵的前两行给出 xclip=nx、yclip=ny,第四行为 [0,0,−1,0];设第三行为 [0,0,A,B],则
zsq=−zAz+B
近平面 z=−n 挤压后仍为 −n,远平面 z=−f 挤压后仍为 −f,代入得到
n−An+Bf−Af+B=−n=−f
两式分别化为 −An+B=−n2 和 −Af+B=−f2。相减得 A(n−f)=n2−f2,因此 A=n+f;回代得 B=nf。挤压矩阵为
Msquish=n0000n0000n+f−100nf0
这里只固定了近平面和远平面的 z,内部点的 z 会被第三行重新映射。挤压后的形状是 x,y∈[−n,n]、z∈[−f,−n] 的长方体。
第二步:正交映射
对上一步得到的长方体套用正交矩阵,取 l=b=−n、r=t=n:
Mortho=n10000n10000n−f2000n−fn+f1
它的 z 行把 [−f,−n] 映射到 [−1,1]:
zndc=n−f2zsq+n−fn+f
代入 zsq=−n 得到 −1,代入 zsq=−f 得到 +1。2/(n−f) 是负数,z 轴在这里翻转。
第三步:合并矩阵
透视矩阵是两步矩阵的乘积:
Mpersp=MorthoMsquish
合并时,Mortho 的平移项乘的是挤压后的 w=−z,不能当作常数 1。因此 z 分量为
zclip=n−f2((n+f)z+nf)+n−fn+f(−z)=n−f(n+f)z+2nf
除以 w=−z 后得到
zndc=(n−f)(−z)(n+f)z+2nf
Mortho 的最后一行是 [0,0,0,1],w 在矩阵乘法中原样保留。因此“先乘两个矩阵、再统一除以 w”与“先除以 w 得到 zsq、再做正交映射”结果相同。
横向坐标的 n 在合并时约掉:挤压给出 xclip=nx,正交矩阵的 x 缩放是 1/n,最终 xclip=x。除以 w=−z 后,xndc=x/(−z);近平面上的 x∈[−n,n] 因此落到 [−1,1]。合并后的矩阵为
Mpersp=1000010000−f−nf+n−100−f−n2nf0
代入近平面上的点 (x,y,−n,1),得到 (x,y,−n,n),除以 w=n 后为 (x/n,y/n,−1)。代入远平面上的点 (x,y,−f,1),第三行给出 zclip=f,除以 w=f 后为 zndc=1。
一般形式
当近平面是 x∈[l,r]、y∈[b,t] 的矩形时,挤压矩阵的横向缩放仍是 n,正交矩阵的横向缩放变为 2/(r−l) 和 2/(t−b)。合并后得到
Mpersp=r−l2n0000t−b2n00r−lr+lt−bt+b−f−nf+n−100−f−n2nf0
第一、二行的第三列来自正交矩阵的平移项与 w=−z 的乘积,用来处理近平面中心不在原点的情况。设垂直视场角为 α,宽高比为 a,则 t=ntan(α/2)、r=at、b=−t、l=−r;代入后可以得到用视场角和宽高比表示的投影矩阵。
变换管线
渲染管线把模型坐标依次变换到世界坐标、相机坐标、裁剪空间:
pclip=MperspMviewMmodelpmodel
矩阵乘法从右往左作用:Mmodel 把模型坐标变换到世界坐标,Mview 把世界坐标变换到相机坐标,Mpersp 把视锥体映射到裁剪空间。裁剪空间仍然是齐次坐标,再除以 w 得到 NDC;视口变换再把 NDC 映射到屏幕像素坐标。