渲染中的变换:从模型空间到屏幕映射

本文详细介绍了三维图形学中的模型变换矩阵,包括旋转、缩放、位移矩阵及其组合应用。还讨论了视图变换、投影变换、视口变换和法线变换矩阵,以及在这些变换中的矩阵运算,如旋转、缩放、位移的分解,以及透视投影和正交投影的区别。此外,还提到了TBN变换矩阵的构造和施密特正交化在切线空间中的作用。
摘要由CSDN通过智能技术生成

模型变换矩阵

模型变换矩阵可以分解为旋转、缩放和位移矩阵,其目的是将物体变换到世界坐标系的中心,然后以此为基准对物体进行旋转、缩放和位移。

旋转矩阵

x , y , z x,y,z x,y,z 轴旋转指定角度,即可等价在任意轴上旋转。按照右手坐标系法则, x x x z z z 轴直接叉乘得到的是 − y -y y 方向,因此 y y y 轴旋转矩阵和其他略有不同。注意,欧拉角的旋转会出现万向锁的现象,需要使用四元数来解决这一问题。
R x ( α ) = ( 1 0 0 0 0 cos ⁡ α − sin ⁡ α 0 0 sin ⁡ α cos ⁡ α 0 0 0 0 1 ) \mathbf{R}_{x}(\alpha)=\left(\begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & \cos \alpha & -\sin \alpha & 0 \\ 0 & \sin \alpha & \cos \alpha & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) Rx(α)=10000cosαsinα00sinαcosα00001

R y ( α ) = ( cos ⁡ α 0 sin ⁡ α 0 0 1 0 0 − sin ⁡ α 0 cos ⁡ α 0 0 0 0 1 ) \mathbf{R}_{y}(\alpha)=\left(\begin{array}{cccc} \cos \alpha & 0 & \sin \alpha & 0 \\ 0 & 1 & 0 & 0 \\ -\sin \alpha & 0 & \cos \alpha & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) Ry(α)=cosα0sinα00100sinα0cosα00001

R z ( α ) = ( cos ⁡ α − sin ⁡ α 0 0 sin ⁡ α cos ⁡ α 0 0 0 0 1 0 0 0 0 1 ) \mathbf{R}_{z}(\alpha)=\left(\begin{array}{cccc} \cos \alpha & -\sin \alpha & 0 & 0 \\ \sin \alpha & \cos \alpha & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) Rz(α)=cosαsinα00sinαcosα0000100001

缩放矩阵

S ( s x , s y , s z ) = ( s x 0 0 0 0 s y 0 0 0 0 s z 0 0 0 0 1 ) \mathbf{S}\left(s_{x}, s_{y}, s_{z}\right)=\left(\begin{array}{cccc} s_{x} & 0 & 0 & 0 \\ 0 & s_{y} & 0 & 0 \\ 0 & 0 & s_{z} & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) S(sx,sy,sz)=sx0000sy0000sz00001

位移矩阵

T ( t x , t y , t z ) = ( 1 0 0 t x 0 1 0 t y 0 0 1 t z 0 0 0 1 ) \mathbf{T}\left(t_{x}, t_{y}, t_{z}\right)=\left(\begin{array}{cccc} 1 & 0 & 0 & t_{x} \\ 0 & 1 & 0 & t_{y} \\ 0 & 0 & 1 & t_{z} \\ 0 & 0 & 0 & 1 \end{array}\right) T(tx,ty,tz)=100001000010txtytz1

视图变换矩阵

视图变换矩阵又称相机变换矩阵,其目的是将世界坐标系下的物体变换到以相机坐标系下,即观察空间。视图变换矩阵可以分解为位移矩阵和旋转矩阵。

位移矩阵

通过修改摄像机的位置,就可以实现摄像机的移动。而世界空间中的物体变换到观察空间就是相对摄像机位置的反方向移动。
T view  = ( 1 0 0 − x e 0 1 0 − y e 0 0 1 − z e 0 0 0 1 ) T_{\text {view }}=\left(\begin{array}{cccc} 1 & 0 & 0 & -x_{e} \\ 0 & 1 & 0 & -y_{e} \\ 0 & 0 & 1 & -z_{e} \\ 0 & 0 & 0 & 1 \end{array}\right) Tview =100001000010xeyeze1

旋转矩阵

设定摄像机位置为 e e e ,垂直向上的向量为 t t t ,观察方向为 g g g 。并默认为看向 − z - z z 轴。因此旋转矩阵实际上是将 g g g 方向旋转到 − z -z z 轴, t t t 方向旋转到 y y y 轴, g × t g\times t g×t 方向旋转到 x x x 轴。

该变换难以得出,但其逆变换很容易得出。而旋转变换是正交变换,其逆矩阵就等于其转置矩阵,因此可以通过逆矩阵反推出旋转矩阵。
R view  − 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 ) R_{\text {view }}^{-1}=\left(\begin{array}{cccc} x_{\hat{g} \times \hat{t}} & x_{t} & x_{-g} & 0 \\ y_{\hat{g} \times \hat{t}} & y_{t} & y_{-g} & 0 \\ z_{\hat{g} \times \hat{t}} & z_{t} & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) Rview 1=xg^×t^yg^×t^zg^×t^0xtytzt0xgygzg00001

R view  = ( 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 ) R_{\text {view }}=\left(\begin{array}{cccc} x_{\hat{\mathrm{g}} \times \hat{t}} & y_{\hat{\mathrm{g}} \times \hat{t}} & z_{\hat{\mathrm{g}} \times \hat{t}} & 0 \\ x_{t} & y_{t} & z_{t} & 0 \\ x_{-g} & y_{-g} & z_{-g} & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) Rview =xg^×t^xtxg0yg^×t^ytyg0zg^×t^ztzg00001

投影变换矩阵

OpenGL \text{OpenGL} OpenGL 为基准,在投影变换阶段,需要将观察空间从右手坐标系变换到左手坐标系下的 NDC \text{NDC} NDC 空间,即从 z z z 轴向屏幕外变换到向屏幕内。在世界坐标系下近平面和远平面的 z z z 值是负的,但我们设定最近参数和最远参数 n , f n,f n,f 为正数。取垂直视场角 f o v fov fov 的一半做正切,即最高参数 t t t 与最近参数 n n n 的比值。再通过屏幕宽高比即可得出最右参数 r r r

tan ⁡ f o v 2 = t n r = t × w h \tan{\frac{fov}{2}} = \frac{t}{n} \\ \\ r = t \times \frac{w}{h} tan2fov=ntr=t×hw

正交投影矩阵

View Space \text{View Space} View Space 在对称情形下, r r r l l l t t t b b b 可以相互抵消,并且实际上一般都是对称的。

M o r t h o = ( 2 r − l 0 0 − r + l r − l 0 2 t − b 0 − t + b t − b 0 0 2 f − n − f + n f − n 0 0 0 1 ) = ( 1 r 0 0 0 0 1 t 0 0 0 0 2 f − n − f + n f − n 0 0 0 1 ) M_{ortho}= \left(\begin{array}{cccc} \frac{2}{r-l} & 0 & 0 & -\frac{r+l}{r-l} \\ 0 & \frac{2}{t-b} & 0 & -\frac{t+b}{t-b} \\ 0 & 0 & \frac{2}{f-n} & -\frac{f+n}{f-n} \\ 0 & 0 & 0 & 1 \end{array}\right)= \left(\begin{array}{cccc} \frac{1}{r} & 0 & 0 & 0 \\ 0 & \frac{1}{t} & 0 & 0 \\ 0 & 0 & \frac{2}{f-n} & -\frac{f+n}{f-n} \\ 0 & 0 & 0 & 1 \end{array}\right) Mortho=rl20000tb20000fn20rlr+ltbt+bfnf+n1=r10000t10000fn2000fnf+n1

位移矩阵

正交投影变换可以分解为位移变换和缩放变换。首先进行位移变换,将 View Space 移动到观察空间的坐标系原点。
T = ( 1 0 0 − r + l 2 0 1 0 − t + b 2 0 0 1 − f + n 2 0 0 0 1 ) = ( 1 0 0 0 0 1 0 0 0 0 1 − f + n 2 0 0 0 1 ) T = \left(\begin{array}{cccc} 1 & 0 & 0 & -\frac{r+l}{2} \\ 0 & 1 & 0 & -\frac{t+b}{2} \\ 0 & 0 & 1 & -\frac{f+n}{2} \\ 0 & 0 & 0 & 1 \end{array}\right)= \left(\begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & -\frac{f+n}{2} \\ 0 & 0 & 0 & 1 \end{array}\right) T=1000010000102r+l2t+b2f+n1=100001000010002f+n1

缩放矩阵

然后再进行缩放变换,将 View Space 的长宽高变换为 [ − 1 , 1 ] [-1,1] [1,1] 的范围,即标准立方体。此时称为齐次裁剪空间。经过齐次裁剪,再对坐标进行透视除法,才变换到 NDC 空间。
S = ( 2 r − l 0 0 0 0 2 t − b 0 0 0 0 2 f − n 0 0 0 0 1 ) = ( 1 r 0 0 0 0 1 t 0 0 0 0 2 f − n 0 0 0 0 1 ) S= \left(\begin{array}{cccc} \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{array}\right)= \left(\begin{array}{cccc} \frac{1}{r} & 0 & 0 & 0 \\ 0 & \frac{1}{t} & 0 & 0 \\ 0 & 0 & \frac{2}{f-n} & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) S=rl20000tb20000fn200001=r10000t10000fn200001

透视投影矩阵

经过这一步变换后的点坐标,实际上 z z z 值不再是线性的了。在进行透视除法时,需要保留齐次坐标的 w w w 值,为后续进行深度测试比较的 z z z 值进行透视矫正插值。

透视投影变换需要先将截锥体形状的 View Space 挤压成长方体形状的的 View Space 后,再进行正交投影变换。将该矩阵和正交投影矩阵左乘后即可得到完整的透视投影矩阵。
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_{persp \rightarrow ortho}= \left(\begin{array}{cccc} n & 0 & 0 & 0 \\ 0 & n & 0 & 0 \\ 0 & 0 & -(n+f) & -nf\\ 0 & 0 & 1 & 0 \end{array}\right) Mpersportho=n0000n0000(n+f)100nf0

M p e r s p = ( 2 n r − l 0 − r + l r − l 0 0 2 n t − b − t + b t − b 0 0 0 − f + n f − n − 2 f n f − n 0 0 − 1 0 ) = ( n r 0 0 0 0 n t 0 0 0 0 − f + n f − n − 2 f n f − n 0 0 − 1 0 ) M_{persp} = \left(\begin{array}{cccc} \frac{2 n}{r-l} & 0 & -\frac{r+l}{r-l} & 0 \\ 0 & \frac{2 n}{t-b} & -\frac{t+b}{t-b} & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{2 f n}{f-n} \\ 0 & 0 & -1 & 0 \end{array}\right)= \left(\begin{array}{cccc} \frac{n}{r} & 0 & 0 & 0 \\ 0 & \frac{n}{t} & 0 & 0 \\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{2 f n}{f-n} \\ 0 & 0 & -1 & 0 \end{array}\right) Mpersp=rl2n0000tb2n00rlr+ltbt+bfnf+n100fn2fn0=rn0000tn0000fnf+n100fn2fn0

视口变换矩阵

视口变换的目的是将 NDC 空间的三维坐标变换到屏幕空间的二维坐标。根据图形API的不同,所规定的屏幕空间的坐标系也不同。以 OpenGL 为标准,我们构建将 NDC 空间的左下变换到原点的变换矩阵。齐次坐标的点坐标经过视口变换后截取 x , y x,y x,y 坐标即为其在屏幕空间下的坐标。
M viewport  = (  width  2 0 0  width  2 0  height  2 0  height  2 0 0 1 0 0 0 0 1 ) M_{\text {viewport }}=\left(\begin{array}{cccc} \frac{\text { width }}{2} & 0 & 0 & \frac{\text { width }}{2} \\ 0 & \frac{\text { height }}{2} & 0 & \frac{\text { height }}{2} \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) Mviewport =2 width 00002 height 0000102 width 2 height 01

法线变换矩阵

法线经过和顶点相同的模型变换往往得不到正确的垂直于三角面的法线,因此我们需要找到使法线正确变换到世界空间的变换矩阵。

由于法线是一个方向矢量没有起点,因此我们可以直接截取模型变换矩阵左上角的 3 × 3 3 \times 3 3×3 子矩阵作为模型变换矩阵 M M M

设三角形 △ A B C \triangle ABC ABC 的切线 T = A − B T = A-B T=AB ,其垂直于面法线 N N N 。且切线 T T T 经过模型变换后为 T ′ T^{\prime} T 应仍然垂直变换后法线 N ′ N^{\prime} N
N ⃗ ′ ⋅ T ⃗ ′ = 0 ( G N ⃗ ) ⋅ ( M T ⃗ ) = 0 \vec{N}^{\prime} \cdot \vec{T}^{\prime} = 0 \\ (G \vec{N} ) \cdot (M \vec{T} ) = 0 N T =0(GN )(MT )=0
设法线经过的变换矩阵为 G G G 。而向量的点积就是向量各维度分量乘积的和,因此可以将点积转换为前一个列向量转置为行向量再和后一个列向量进行分量相乘运算。
( G N ⃗ ) T ∗ ( M T ⃗ ) = 0 N ⃗ T G T M T ⃗ = 0 ( G \vec{N})^T * (M \vec{T} ) = 0 \\ \vec{N}^TG^TM \vec{T} =0 (GN )T(MT )=0N TGTMT =0

均匀缩放的法线矩阵

切线 T T T 应始终垂直于法线 N N N ,切线 T T T 经过变换 G T M G^TM GTM 应没有发生变化,即 G T M G^TM GTM 为单位矩阵 E E E

如果模型变换矩阵 M M M 的缩放变换是均匀的,那么模型变换矩阵 M M M 就是一个可逆的旋转矩阵,因此法线 N N N 经过的法线变换 G G G 就是模型变换矩阵 M M M 逆矩阵的转置。

注意,经过变换的法线 N N N 不能保证其仍然是单位长度,因此需要对法线重新归一化。但如果模型变换矩阵只包含了旋转变换,则法线变换矩阵 G G G 就是模型变换矩阵 M M M ,此时无需对法线进行归一化。
G T M = E G T = M − 1 G = ( M − 1 ) T G^TM = E \\ G^T=M^{-1} \\ G = (M^{-1})^{T} GTM=EGT=M1G=(M1)T

非均匀缩放的法线矩阵

如果模型变换矩阵 M M M 含有不均匀的缩放变换,则该矩阵可能无法求出逆矩阵。这是因为缩放变换必须满足方阵对角线上的元素都不为 0 0 0 才是可逆的。

已知矩阵的伴随矩阵的特性有 A A ∗ = ∣ A ∣ E AA^*=|A|E AA=AE ,因此直接将伴随矩阵替换掉逆矩阵同样可以得到法线变换矩阵 G G G 。且其常数因子会被我们后续对法线的归一化所消除。
G = ( M ∗ ) T G = (M^*)^T G=(M)T

TBN 变换矩阵

施密特标准正交化

施密特正交化可以由非线性相关的一组向量 ( α 1 , α 2 , α 3 ) (\alpha_1,\alpha_2,\alpha_3) (α1,α2,α3) 构造出互相正交的一组向量 ( β 1 , β 2 , β 3 ) (\beta_1,\beta_2,\beta_3) (β1,β2,β3) 。再对构造出的向量进行归一化就得到了一组单位基向量 ( γ 1 , γ 2 , γ 3 ) (\gamma_1,\gamma_2,\gamma_3) (γ1,γ2,γ3)
β 1 = α 1 β 2 = α 2 − ( α 2 , β 1 ) ( β 1 , β 1 ) β 1 β 3 = α 3 − ( α 3 , β 1 ) ( β 1 , β 1 ) β 1 − ( α 3 , β 2 ) ( β 2 , β 2 ) β 2 \begin{aligned} \beta_1 &= \alpha_1 \\ \beta_2 &= \alpha_2 - \frac{(\alpha_2,\beta_1)}{(\beta_1,\beta_1)} \beta_1 \\ \beta_3 &= \alpha_3 - \frac{(\alpha_3,\beta_1)}{(\beta_1,\beta_1)} \beta_1 - \frac{(\alpha_3,\beta_2)}{(\beta_2,\beta_2)} \beta_2 \end{aligned} β1β2β3=α1=α2(β1,β1)(α2,β1)β1=α3(β1,β1)(α3,β1)β1(β2,β2)(α3,β2)β2

γ 1 = β 1 ∣ ∣ β 1 ∣ ∣ , γ 2 = β 2 ∣ ∣ β 2 ∣ ∣ , γ 3 = β 3 ∣ ∣ β 3 ∣ ∣ \gamma_1 = \frac{\beta_1}{||\beta_1||}, \gamma_2 = \frac{\beta_2}{||\beta_2||}, \gamma_3 = \frac{\beta_3}{||\beta_3||} γ1=β1β1,γ2=β2β2,γ3=β3β3

构造切线空间

以顶点着色阶段插值得到的三角形内一点的世界空间法线 n n n z z z 轴构建切线空间,则需要再取三角形纹理坐标系的 u u u 轴映射到三维空间为切线方向 t t t ,对 n , t n,t n,t 进行施密特标准正交化即可得到一组正交的单位基向量。
n ⊥ = n t ⊥ = n o r m a l i z e ( t − ( t ⋅ n ) n ) b ⊥ = n ⊥ × t ⊥ \begin{array} {l} n_{\perp} = n \\ t_{\perp} = normalize(t-(t \cdot n) n) \\ b_{\perp} = n_{\perp} \times t_{\perp} \end{array} n=nt=normalize(t(tn)n)b=n×t

以上得出的是将切线空间法线贴图中得到的法线变换到世界空间的 TBN 矩阵,如果用模型空间法线建立切线空间则变换的结果是模型空间法线。

如果要在切线空间中运算,只需要将世界空间法线左乘 TBN 矩阵的逆矩阵即可。而TBN矩阵是一个正交矩阵,其逆矩阵等于其转置矩阵。
M T B N = ( T x T y T z 0 B x B y B z 0 N x N y N z 0 0 0 0 1 ) M_{T B N}=\left(\begin{array}{cccc} T_{x} & T_{y} & T_{z} & 0 \\ B_{x} & B_{y} & B_{z} & 0 \\ N_{x} & N_{y} & N_{z} & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) MTBN=TxBxNx0TyByNy0TzBzNz00001

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值