计算机图形学 - MVP 矩阵的推导

0 说明

以下所有内容均为课程 GAMES101 的笔记,建议结合视频和 PPT 使用

1 Model Transformation

这一步就是把物体顶点的坐标从模型坐标系转化成世界坐标,通俗地讲,就是拍照前要把物体摆放到合适的位置。例如在模型坐标中, ( ± 0.5 , ± 0.5 , ± 0.5 ) (\pm 0.5,\pm0.5,\pm0.5) (±0.5,±0.5,±0.5) 是一个立方体的八个顶点坐标。但是这个立方体可以被我们通过平移、旋转、缩放,以各种姿势出现在世界坐标系中的任意位置,而这一步是通过三维仿射变换实现的。

假设有齐次坐标下的顶点 V V V,依次用仿射变换矩阵 P 0 , P 1 , . . . P n P_0,P_1,...P_n P0,P1,...Pn 去左乘 V V V,那么 Model 变换矩阵 M m o d e l = P n P n − 1 ⋯ P 0 M_{model}=P_nP_{n-1}\cdots P_0 Mmodel=PnPn1P0(因为变换矩阵是不断左乘上去的,注意顺序)

2 View / Camera Transformation

现在物体已经摆放完毕,第二步就是确定摄像机的状态,并且从摄像机的视角确定物体的坐标。

假设在左手坐标系下(GAMES101 是右手系,区别不大),我们首先用一个点坐标 e → \overrightarrow{e} e 表示相机的位置(eye position),同时用两个向量来确定相机的旋转:

  • g ^ \hat{g} g^,表示相机看向的方向(gaze at)
  • t ^ \hat{t} t^,表示相机向上的朝向(top)

同时,通过叉乘可以确定相机坐标系的最后一个基向量 g ^ × t ^ \hat{g}\times \hat{t} g^×t^

我们设定一个理想的(或者说默认的)状态,相机位于坐标原点,并且看向 z 轴正方向,向上朝向 y 轴正方向,这样 g ^ × t ^ \hat{g}\times \hat{t} g^×t^ 就指向 x 轴正方向

对于一般的相机,我们需要找到一个变换矩阵 M v i e w M_{view} Mview 将一个顶点从世界坐标系变换到相机坐标系中,因为相机和顶点的相对位置和旋转是不变的,所以也可以认为 M v i e w M_{view} Mview 是将一般的相机变换到前文所述的理想状态。这个步骤可以拆解成两步:先把相机平移到原点,再把相机旋转成理想状态。

平移矩阵很好写:
T v i e w = [ 1 0 0 − x e 0 1 0 − y e 0 0 1 − z e 0 0 0 1 ] \begin{gathered} T_{view}=\begin {bmatrix} 1&0&0&-x_e \\ 0&1&0&-y_e \\ 0&0&1&-z_e \\ 0&0&0&1 \\\end{bmatrix} \quad \end{gathered} Tview=100001000010xeyeze1

考虑旋转矩阵的逆矩阵:
R v i e w − 1 = [ x g ^ × t ^ x t ^ x g ^ 0 y g ^ × t ^ y t ^ y g ^ 0 z g ^ × t ^ z t ^ z g ^ 0 0 0 0 1 ] \begin{gathered} R^{-1}_{view}=\begin {bmatrix} x_{\hat{g}\times\hat{t}}&x_{\hat{t}}&x_{\hat{g}}&0 \\ y_{\hat{g}\times\hat{t}}&y_{\hat{t}}&y_{\hat{g}}&0 \\ z_{\hat{g}\times\hat{t}}&z_{\hat{t}}&z_{\hat{g}}&0 \\ 0&0&0&1 \\\end{bmatrix} \quad \end{gathered} Rview1=xg^×t^yg^×t^zg^×t^0xt^yt^zt^0xg^yg^zg^00001
推导过程: R v i e w − 1 R^{-1}_{view} Rview1 描述的是世界坐标系到相机坐标系的旋转过程(此时相机已经位于原点)。考虑世界坐标系下 x 轴方向的基向量 a → = [ 1 , 0 , 0 , 0 ] T \overrightarrow{a}=[1,0,0,0]^T a =[1,0,0,0]T,旋转过后应该等于相机坐标系下的基向量 [ x g ^ × t ^ , y g ^ × t ^ , z g ^ × t ^ , 0 ] T [x_{\hat{g}\times\hat{t}},y_{\hat{g}\times\hat{t}},z_{\hat{g}\times\hat{t}},0]^T [xg^×t^,yg^×t^,zg^×t^,0]T

也就是 R v i e w − 1 [ 1 , 0 , 0 , 0 ] T = [ x g ^ × t ^ , y g ^ × t ^ , z g ^ × t ^ , 0 ] T R^{-1}_{view}[1,0,0,0]^T=[x_{\hat{g}\times\hat{t}},y_{\hat{g}\times\hat{t}},z_{\hat{g}\times\hat{t}},0]^T Rview1[1,0,0,0]T=[xg^×t^,yg^×t^,zg^×t^,0]T,代入后可以算出 R v i e w − 1 R^{-1}_{view} Rview1 的第一列。对于第二列和第三列可以通过 y 轴和 z 轴的旋转结果得出

并且,旋转矩阵是正交矩阵,它的逆矩阵等于它的转置,所以
R v i e w = [ x g ^ × t ^ y g ^ × t ^ z g ^ × t ^ 0 x t ^ y t ^ z t ^ 0 x g ^ y g ^ z g ^ 0 0 0 0 1 ] \begin{gathered} R_{view}=\begin {bmatrix} x_{\hat{g}\times\hat{t}}&y_{\hat{g}\times\hat{t}}&z_{\hat{g}\times\hat{t}}&0 \\ x_{\hat{t}}&y_{\hat{t}}&z_{\hat{t}}&0 \\ x_{\hat{g}}&y_{\hat{g}}&z_{\hat{g}}&0 \\ 0&0&0&1 \\\end{bmatrix} \quad \end{gathered} Rview=xg^×t^xt^xg^0yg^×t^yt^yg^0zg^×t^zt^zg^00001

那么就得到这个阶段的变换矩阵 M v i e w = R v i e w T v i e w M_{view}=R_{view}T_{view} Mview=RviewTview

3 Project Transformation

现在我们已经站在相机的视角看物体了,还差最后的按下快门。投影一般有两种方法:正交投影和透视投影,区别在于透视投影下的物体近大远小(所以鸽子为什么那么大?)。我们这一步的目的是把视野中的所有顶点摆放到 [ − 1 , 1 ] 3 [-1,1]^3 [1,1]3 的标准立方体中,方便渲染管线的后续操作。

先推导较为简单的正交投影,透视投影可以转化为正交投影。通过上述相机的参数可以确定视锥体(在正交投影下是一个长方体)在坐标系中的范围,定义在 x 轴上范围是 [ l , r ] [l,r] [l,r],在 y 轴上范围是 [ b , t ] [b,t] [b,t],在 z 轴上范围是 [ n , f ] [n,f] [n,f]。我们要把这个长方体变换成标准立方体,需要先把长方体中心平移到原点,然后在 x,y,z 三个方向上进行放缩即可。于是有:
T o r t h o = [ 1 0 0 − l + r 2 0 1 0 − b + t 2 0 0 1 − n + f 2 0 0 0 1 ] S o r t h o = [ 2 r − l 0 0 0 0 2 t − b 0 0 0 0 2 f − n 0 0 0 0 1 ] M o r t h o = S o r t h o T o r t h o \begin{gathered} T_{ortho}=\begin {bmatrix} 1&0&0&-\frac{l+r}{2} \\ 0&1&0&-\frac{b+t}{2} \\ 0&0&1&-\frac{n+f}{2} \\ 0&0&0&1 \\\end{bmatrix} \quad \end{gathered} \begin{gathered} S_{ortho}=\begin {bmatrix} \frac{2}{r-l}&0&0&0 \\ 0&\frac{2}{t-b}&0&0 \\ 0&0&\frac{2}{f-n}&0 \\ 0&0&0&1 \\\end{bmatrix} \quad \end{gathered}\\ M_{ortho}=S_{ortho}T_{ortho} Tortho=1000010000102l+r2b+t2n+f1Sortho=rl20000tb20000fn200001Mortho=SorthoTortho

接下来进行透视投影到正交投影的变换,就是把透视投影的视锥体“压缩”成正交变换的长方体。过程中 n n n f f f 不变,最终长方体的宽和高等于近平面的宽和高。为了得到(只是猜出这个矩阵长什么样,不涉及证明)这个变换矩阵 M p e r s p → o r t h o M_{persp\rightarrow ortho} Mpersportho,考虑远平面上沿的任意点 [ x , y , z , 1 ] T [x,y,z,1]^T [x,y,z,1]T,假设其压缩后的坐标是 [ x ′ , y ′ , z ′ , 1 ] T [x',y',z',1]^T [x,y,z,1]T,根据我们压缩的规则,最终远平面上沿的高度等于近平面上沿的高度,根据相似三角形的关系,z 轴分量上的比例是 n z \frac{n}{z} zn,那么有 x ′ = n x z x'=\frac{nx}{z} x=znx y ′ = n y z y'=\frac{ny}{z} y=zny,压缩后的坐标可以写成 [ n x z , n y z , ? , 1 ] T [\frac{nx}{z},\frac{ny}{z},?,1]^T [znx,zny,,1]T(暂时不管第三个分量),对齐次坐标乘以实数不改变其位置,所以压缩后的坐标可以写成 [ n x , n y , ? , z ] T [nx,ny,?,z]^T [nx,ny,,z]T。于是根据 M p e r s p → o r t h o [ x , y , z , 1 ] T = [ n x , n y , ? , z ] T M_{persp\rightarrow ortho}[x,y,z,1]^T=[nx,ny,?,z]^T Mpersportho[x,y,z,1]T=[nx,ny,,z]T 可以得到以下信息:
M p e r s p → o r t h o = [ n 0 0 0 0 n 0 0 ? ? ? ? 0 0 1 0 ] \begin{gathered} M_{persp\rightarrow ortho}=\begin {bmatrix} n&0&0&0 \\ 0&n&0&0 \\ ?&?&?&? \\ 0&0&1&0 \\\end{bmatrix} \quad \end{gathered} Mpersportho=n0?00n?000?100?0

并且,近平面上的任意点 [ x , y , n , 1 ] T [x,y,n,1]^T [x,y,n,1]T 在压缩后坐标不应该发生变化,有: M p e r s p → o r t h o [ x , y , n , 1 ] T = [ n x , n y , n 2 , n ] T M_{persp\rightarrow ortho}[x,y,n,1]^T=[nx,ny,n^2,n]^T Mpersportho[x,y,n,1]T=[nx,ny,n2,n]T,计算后可以得到以下结果。我们只剩下第三行的两个未知数 A A A B B B 没有确定了:
M p e r s p → o r t h o = [ n 0 0 0 0 n 0 0 0 0 A B 0 0 1 0 ] \begin{gathered} M_{persp\rightarrow ortho}=\begin {bmatrix} n&0&0&0 \\ 0&n&0&0 \\ 0&0&A&B \\ 0&0&1&0 \\\end{bmatrix} \quad \end{gathered} Mpersportho=n0000n0000A100B0

如果只考虑第三行,那么根据 M p e r s p → o r t h o [ x , y , n , 1 ] T = [ n x , n y , n 2 , n ] T M_{persp\rightarrow ortho}[x,y,n,1]^T=[nx,ny,n^2,n]^T Mpersportho[x,y,n,1]T=[nx,ny,n2,n]T 还可以得到 [ 0 , 0 , A , B ] ⋅ [ x , y , n , 1 ] T = n 2 [0,0,A,B]\cdot [x,y,n,1]^T=n^2 [0,0,A,B][x,y,n,1]T=n2。远平面上任意点 [ x , y , f , 1 ] [x,y,f,1] [x,y,f,1] 压缩后的 z 分量也不会变化,有 [ 0 , 0 , A , B ] ⋅ [ x , y , f , 1 ] T = f 2 [0,0,A,B]\cdot [x,y,f,1]^T=f^2 [0,0,A,B][x,y,f,1]T=f2,联立上述两个式子可以解出:
{ A = n + f B = − n f M p e r s p → o r t h o = [ n 0 0 0 0 n 0 0 0 0 n + f − n f 0 0 1 0 ] M p r o j e c t = M o r t h o M p e r s p → o r t h o \begin{cases} A=n+f\\ B=-nf \end{cases}\\ \\[10pt] \begin{gathered} M_{persp\rightarrow ortho}=\begin {bmatrix} n&0&0&0 \\ 0&n&0&0 \\ 0&0&n+f&-nf \\ 0&0&1&0 \\\end{bmatrix} \\[10pt] \quad\\ M_{project}=M_{ortho}M_{persp\rightarrow ortho} \end{gathered} {A=n+fB=nfMpersportho=n0000n0000n+f100nf0Mproject=MorthoMpersportho

此外,补充一点,在实际写软渲染器的时候,透视投影需要先确定相机的几个关键参数:

  • n e a r near near f a r far far:决定了相机在 z 轴上的可视距离。因为我们是左手系,相机看向 z 轴正方向,所以 n e a r near near f a r far far 都是正的并且 n e a r < f a r nearnear<far
  • f o v y fov_y fovy:在 y 轴上的视场角,决定了在 y 轴方向上的可视角度
  • r a t i o ratio ratio:近平面上的宽高比

通过上述参数可以确定压缩后长方体的各项参数:显然, n = n e a r n=near n=near f = f a r f=far f=far。根据 y O z yOz yOz 平面上的三角形关系, t = n tan ⁡ ( 1 2 f o v y ) t=n\tan(\frac{1}{2}fov_y) t=ntan(21fovy) b = − t b=-t b=t r = t × r a t i o r=t\times ratio r=t×ratio l = − r l=-r l=r

你可能感兴趣的:(图形学,图形学)