[从零开始的SoftRenderer]2.坐标变换

  一个物体要投影到屏幕上需要依次经过 Model(世界矩阵,转换到世界空间)、View(视图矩阵,转换到观察空间/摄像机空间)、Projection(投影矩阵,转换到裁剪空间),合起来就是常见的MVP矩阵。
  Model矩阵和View矩阵很好理解,只是单纯的坐标系变换(注:Unity里摄像机坐标系采用的是右手系,与其世界坐标系相反,算是一个小的坑点),如果有不理解的推荐一个视频课程,线性代数的本质,这里就不详细说明了。

齐次坐标

  在介绍投影矩阵前,我们先来了解下齐次坐标。齐次坐标就是将一个原本是n维的向量用一个n+1维向量来表示,比如三维向量 ( x , y , z ) \displaystyle (x,y,z) (x,y,z)采用 ( x , y , z , w ) \displaystyle (x,y,z,w) (x,y,z,w)来表示。其存在的意义有篇文章介绍的很好,这里给出原文译文链接。而在线性变换过程中,齐次坐标的作用主要是提供了位移功能。
[ 1 0 0 T x 0 1 0 T y 0 0 1 T z 0 0 0 1 ] ⋅ ( x y z 1 ) = ( x + T x y + T y z + T z 1 ) \begin{bmatrix} \color{red}1 & \color{red}0 & \color{red}0 & \color{red}{T_x} \\ \color{green}0 & \color{green}1 & \color{green}0 & \color{green}{T_y} \\ \color{blue}0 & \color{blue}0 & \color{blue}1 & \color{blue}{T_z} \\ \color{purple}0 & \color{purple}0 & \color{purple}0 & \color{purple}1 \end{bmatrix} \cdot \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x + \color{red}{T_x} \\ y + \color{green}{T_y} \\ z + \color{blue}{T_z} \\ 1 \end{pmatrix} 100001000010TxTyTz1xyz1=x+Txy+Tyz+Tz1  上面就是一个标准的位移变换,移动的距离为 ( T x , T y , T z ) \displaystyle (\color{red}{T_x},\color{green}{T_y},\color{blue}{T_z}) (Tx,Ty,Tz),而齐次坐标 w \displaystyle w w则为1(当 w \displaystyle w w为0时,则说明 ( x , y , z ) \displaystyle (x,y,z) (x,y,z)代表一个不可位移的向量)。

投影矩阵

  这里先推荐一篇很好的投影文章
  投影有两种方式,一种是近大远小的透视投影,另一种则是远近一样大的正交投影。我们的摄像机会有一个可视范围,投影要做的其实就是将这个可视范围转换成标准设备坐标(NDC) ( − 1 ⩽ x ⩽ 1 , − 1 ⩽ y ⩽ 1 , − 1 ⩽ z ⩽ 1 ) \displaystyle ( -1\leqslant x\leqslant 1,-1\leqslant y\leqslant 1,-1\leqslant z\leqslant 1) (1x1,1y1,1z1),超出此范围的顶点则会进行裁剪。

透视投影

在这里插入图片描述
  如上图所示,左边是我们摄像机的可视范围,右边则是NDC范围。透视投影的可视范围是一个锥形区域,现在我们需要想办法将其转换成一个正方体范围。这里的 n , f \displaystyle n, f n,f表示近平面和远平面距摄像机的距离, l 、 r 、 t 、 b \displaystyle l、r、t、b lrtb则为近平面的左、右、上、下。
在这里插入图片描述  我们先考虑如何求投影坐标的 x \displaystyle x x。其实观察空间的原点和目标点相连的直线与近平面相较的坐标点,就是投影的坐标点,而这一点我们可以很容易的通过相似三角形等比计算出来。所以可得 x p = n ⋅ x e − z e \displaystyle x_p = \frac{n\cdot x_e}{-z_e} xp=zenxe(注:这里 x e \displaystyle x_e xe表示该点在观察空间上的 x \displaystyle x x坐标)。同理, y p = n ⋅ y e − z e \displaystyle y_p = \frac{n\cdot y_e}{-z_e} yp=zenye。我们可以先观察下这个坐标, z e \displaystyle {z_e} ze在分母上,这是一般的矩阵变换不可能得到的结果,我们需要借助齐次坐标来实现,所以我们首先可以确定的是,经透视投影矩阵变换后的坐标的 w \displaystyle w w,一定是 z e \displaystyle {z_e} ze的倍数。于是透视投影矩阵的第四行可以确定了。
( x c y c z c w c ) = ( ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 0 0 − 1 0 ) ( x e y e z e w e ) , ∴ w c = − z e \left( \begin{matrix} x_c\\ y_c\\ z_c\\ w_c \end{matrix} \right)=\left( \begin{matrix} \cdot & \cdot &\cdot &\cdot\\ \cdot & \cdot &\cdot &\cdot\\ \cdot & \cdot &\cdot &\cdot\\ 0 & 0 & -1 & 0 \end{matrix} \right) \left( \begin{matrix} x_e\\ y_e\\ z_e\\ w_e \end{matrix} \right), \therefore w_c=-z_e xcyczcwc=0010xeyezewe,wc=ze  接下来我们来确定 x \displaystyle x x y \displaystyle y y坐标该如何变换。以 x \displaystyle x x为例,投影到近平面的点 x p \displaystyle x_p xp的范围是 [ l , r ] \displaystyle [l,r] [l,r],我们的目标是将其转换为NDC下的坐标点 x n \displaystyle x_n xn(注:这里的 x n \displaystyle x_n xn是齐次坐标进行了转换后的结果,即 x n = x c w c = x c − z e \displaystyle x_n=\frac{x_c}{w_c}=\frac{x_c}{-z_e} xn=wcxc=zexc),而 l \displaystyle l l r \displaystyle r r是对称的,即 l + r = 0 \displaystyle l+r = 0 l+r=0。所以我们可推得公式:
x n = x p r = n x e − z e r x_n=\frac{x_p}{r}=\frac{nx_e}{-z_er} xn=rxp=zernxe  同理可得:
y n = y p t = n y e − z e t y_n=\frac{y_p}{t}=\frac{ny_e}{-z_et} yn=typ=zetnye  所以矩阵的前两行我们又可以确定了
( x c y c z c w c ) = ( n r 0 0 0 0 n t 0 0 ⋅ ⋅ ⋅ ⋅ 0 0 − 1 0 ) ( x e y e z e w e ) \left( \begin{matrix} x_c\\ y_c\\ z_c\\ w_c \end{matrix} \right)=\left( \begin{matrix} \frac{n}{r} & 0 & 0 & 0\\ 0 & \frac{n}{t} & 0 & 0\\ \cdot & \cdot & \cdot & \cdot\\ 0 & 0 & -1 & 0 \end{matrix} \right) \left( \begin{matrix} x_e\\ y_e\\ z_e\\ w_e \end{matrix} \right) xcyczcwc=rn000tn0001000xeyezewe  最后我们来确定 z \displaystyle z z轴的变换。在观察空间中 z e \displaystyle z_e ze的范围是 [ − n , − f ] \displaystyle [-n,-f] [n,f],我们希望也能将其转换成NDC空间的 [ − 1 , 1 ] \displaystyle [-1,1] [1,1]。因为这个不可能和 x , y \displaystyle x,y x,y有关,所以我们设矩阵为
( x c y c z c w c ) = ( n r 0 0 0 0 n t 0 0 0 0 A B 0 0 − 1 0 ) ( x e y e z e w e ) \left( \begin{matrix} x_c\\ y_c\\ z_c\\ w_c \end{matrix} \right)=\left( \begin{matrix} \frac{n}{r} & 0 & 0 & 0\\ 0 & \frac{n}{t} & 0 & 0\\ 0 & 0 & A & B\\ 0 & 0 & -1 & 0 \end{matrix} \right) \left( \begin{matrix} x_e\\ y_e\\ z_e\\ w_e \end{matrix} \right) xcyczcwc=rn0000tn0000A100B0xeyezewe  可推得
z n = z c w c = A z e + B w e − z e = A z e + B − z e z_n =\frac{z_c}{w_c}= \frac{Az_e + Bw_e}{-z_e}= \frac{Az_e + B}{-z_e} zn=wczc=zeAze+Bwe=zeAze+B  我们可以分别将 ( − 1 , 1 ) \displaystyle (-1,1) (1,1)代入 z n \displaystyle z_n zn ( − n , − f ) \displaystyle (-n,-f) (n,f)代入 z e \displaystyle z_e ze得到方程组
{ − A n + B = − n − A f + B = f \left\{ \begin{array}{lr} -An + B = -n &\\ -Af + B = f & \end{array} \right. {An+B=nAf+B=f  解该方程组得到
{ A = − f + n f − n B = − 2 f n f − n \left\{ \begin{array}{lr} A = -\frac{f+n}{f-n}&\\ B = -\frac{2fn}{f-n}& \end{array} \right. {A=fnf+nB=fn2fn  所以最终可推得透视投影矩阵
( x c y c z c w c ) = ( 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 ) ( x e y e z e w e ) \left( \begin{matrix} x_c\\ y_c\\ z_c\\ w_c \end{matrix} \right)=\left( \begin{matrix} \frac{n}{r} & 0 & 0 & 0\\ 0 & \frac{n}{t} & 0 & 0\\ 0 & 0 & -\frac{f+n}{f-n} & -\frac{2fn}{f-n}\\ 0 & 0 & -1 & 0 \end{matrix} \right) \left( \begin{matrix} x_e\\ y_e\\ z_e\\ w_e \end{matrix} \right) xcyczcwc=rn0000tn0000fnf+n100fn2fn0xeyezewe

正交投影

在这里插入图片描述
  相较于透视投影,正交投影就简单太多了,其转换过程与一般的坐标系变换并没有太大分别,这里就不展开谈了,直接上矩阵:
( 1 r 0 0 0 0 1 t 0 0 0 0 − 2 f − n − f + n f − n 0 0 0 1 ) \left( \begin{matrix} \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{matrix} \right) r10000t10000fn2000fnf+n1

视口矩阵

  视口矩阵既是将NDC下的坐标转换为屏幕上的指定像素区域,也可以理解为该摄像机在屏幕上的显示区域。我这里就偷懒直接覆盖全屏幕了。
( w i d t h 2 0 0 w i d t h 2 0 h e i g h t 2 0 h e i g h t 2 0 0 1 0 0 0 0 1 ) \left( \begin{matrix} \frac{width}{2} & 0 & 0 & \frac{width}{2}\\ 0 & \frac{height}{2} & 0 & \frac{height}{2}\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & 1 \end{matrix} \right) 2width00002height0000102width2height01

总结

  这一章中,我们介绍了三维空间中的坐标是如何一步步转换为屏幕上坐标的,其实这里结合上一章中的绘制三角形,我们就已经可以尝试去渲染3d模型了。所以,下一章则会介绍下最基本的渲染管线。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值