渲染中的空间转换

概述

本文的图片来源和主要参考文献为:Fundamentals of Computer Graphics

渲染中的空间转换如下图所示:
空间变换
在渲染过程中会涉及到五个空间以及四个转换.

初始空间变换目标空间
模型空间(Object space)模型变换(Modeling transformation)世界空间(World space)
世界空间(World space)观察变换(Camera transformation)观察空间 (Camera space)
观察空间 (Camera space)投影变换(Projection transformation)裁剪空间 (Clip space)
裁剪空间 (Clip space)归一化归一化设备坐标(NDC)
归一化设备坐标(NDC)屏幕映射(Viewport transformation)屏幕空间(Screen space)

屏幕映射(Viewport transformation)

基础知识

像素坐标约定

在这里插入图片描述
像素值其实就是一个个的小格子,它的索引及坐标都是整数.但是我们现实中使用的坐标都为实数坐标.
像素坐标无固定的定义,这里仅作为一种约定方便讨论.
这里假设横向格子为 n x n_x nx,纵向格子为 n y n_y ny. 那么我们实际使用的坐标区域为:
R = [ − 0.5 , n x − 0.5 ] × [ − 0.5 , n y − 0.5 ] R=[-0.5,n_x-0.5]\times[-0.5,n_y-0.5] R=[0.5,nx0.5]×[0.5,ny0.5]

窗口转换

窗口转换的目标为构建一个映射,把矩形A中的点映射到矩形B中.
这里假定矩形A为 [ x l , x h ] × [ y l , y h ] [x_l,x_h]\times[y_l,y_h] [xl,xh]×[yl,yh]
矩形B为 [ x l ′ , x h ′ ] × [ y l ′ , y h ′ ] [x_l',x_h']\times[y_l',y_h'] [xl,xh]×[yl,yh].
一种方法是先把A缩放到和B一样的大小,然后再通过平移让矩阵对齐.
但是由于直接缩放会让平移的参数难以获得,另一种更直观的方案如下图所示:
在这里插入图片描述
我们先让矩形A的左下角平移至原点,然后进行缩放使得矩形A的大小和矩阵B的大小一致.
其次我们再通过平移使得矩形A和矩形B对齐即可.
这里我们不用过多关心构建的过程,因为我们经我们组合后只会获得一个最终矩阵. 所以在构建过程中越简单越直观越好.
我们使用列向量来表示坐标,所以矩阵的应用从右手边开始. 我们矩阵如下:
窗 口 转 换 = ( 平 移 使 A 和 B 对 齐 ) ( 缩 放 A 使 A 大 小 和 B 一 致 ) ( 平 移 A 使 左 下 角 到 原 点 ) 窗口转换=(平移使A和B对齐) (缩放A使A大小和B一致)(平移A使左下角到原点) =(使AB)(A使AB)(A使)
即:
w i n d o w = t r a n s l a t e ( x l ′ , y l ′ )    s c a l e ( x h ′ − x l ′ x h − x l , y h ′ − y l ′ y h − y l )    t r a n s l a t e ( − x l , − y l ) window=translate(x_l',y_l') \; scale(\frac{x_h'-x_l'}{x_h-x_l},\frac{y_h'-y_l'}{y_h-y_l}) \;translate(-x_l,-y_l) window=translate(xl,yl)scale(xhxlxhxl,yhylyhyl)translate(xl,yl)
使用矩阵表示:
w i n d o w = [ 0 0 0 x l ′ 0 0 0 y l ′ 0 0 0 0 0 0 0 1 ] [ x h ′ − x l ′ x h − x l 0 0 0 0 y h ′ − y l ′ y h − y l 0 0 0 0 0 0 0 0 0 1 ] [ 0 0 0 − x l 0 0 0 − y l 0 0 0 0 0 0 0 1 ] window= \begin{bmatrix} 0 & 0&0&x_l'\\ 0 & 0&0&y_l' \\ 0 & 0&0&0 \\ 0 & 0&0&1 \\ \end{bmatrix} \begin{bmatrix} \frac{x_h'-x_l'}{x_h-x_l} & 0&0&0 \\ 0 & \frac{y_h'-y_l'}{y_h-y_l}&0&0 \\ 0 & 0&0&0 \\ 0 & 0&0&1 \\ \end{bmatrix} \begin{bmatrix} 0 & 0&0&-x_l \\ 0 & 0&0&-y_l \\ 0 & 0&0&0 \\ 0 & 0&0&1 \\ \end{bmatrix} window=000000000000xlyl01xhxlxhxl0000yhylyhyl0000000001000000000000xlyl01
w i n d o w = [ x h ′ − x l ′ x h − x l 0 0 x l ′ x h − x h ′ x l x h − x l 0 y h ′ − y l ′ y h − y l 0 y l ′ y h − y h ′ y l y h − y l 0 0 0 0 0 0 0 1 ] window = \begin{bmatrix} \frac{x_h'-x_l'}{x_h-x_l} & 0&0&\frac{x_l'x_h-x_h'x_l}{x_h-x_l} \\ 0 & \frac{y_h'-y_l'}{y_h-y_l}&0&\frac{y_l'y_h-y_h'y_l}{y_h-y_l} \\ 0 & 0&0&0 \\ 0 & 0&0&1 \\ \end{bmatrix} window=xhxlxhxl0000yhylyhyl000000xhxlxlxhxhxlyhylylyhyhyl01
扩展一维同理.
假设我们要把长方体 [ x l , x h ] × [ y l , y h ] × [ z l , z h ] [x_l,x_h]\times[y_l,y_h]\times[z_l,z_h] [xl,xh]×[yl,yh]×[zl,zh]映射到 [ x l ′ , x h ′ ] × [ y l ′ , y h ′ ] × [ z l ′ , z h ′ ] [x_l',x_h']\times[y_l',y_h']\times[z_l',z_h'] [xl,xh]×[yl,yh]×[zl,zh]:
w i n d o w = [ x h ′ − x l ′ x h − x l 0 0 x l ′ x h − x h ′ x l x h − x l 0 y h ′ − y l ′ y h − y l 0 y l ′ y h − y h ′ y l y h − y l 0 0 z h ′ − z l ′ z h − z l z l ′ z h − z h ′ z l z h − z l 0 0 0 1 ] window = \begin{bmatrix} \frac{x_h'-x_l'}{x_h-x_l} & 0&0&\frac{x_l'x_h-x_h'x_l}{x_h-x_l} \\ 0 & \frac{y_h'-y_l'}{y_h-y_l}&0&\frac{y_l'y_h-y_h'y_l}{y_h-y_l} \\ 0 & 0&\frac{z_h'-z_l'}{z_h-z_l}&\frac{z_l'z_h-z_h'z_l}{z_h-z_l} \\ 0 & 0&0&1 \\ \end{bmatrix} window=xhxlxhxl0000yhylyhyl0000zhzlzhzl0xhxlxlxhxhxlyhylylyhyhylzhzlzlzhzhzl1

屏幕映射

在这一步中分别牵扯到两个空间: 归一化设备坐标(下文简称NDC)和屏幕空间.
这里做以下假定:

  1. 我们需要去渲染的所有顶点都在一个小立方体里, 小立方体的范围为: ( x , y , z ) ∈ [ − 1 , 1 ] 3 (x,y,z)\in[-1,1]^3 (x,y,z)[1,1]3.
  2. 摄像机朝向为-z方向,up方向为+y方向.
    现在我们需要去做的是把正方形 [ − 1 , 1 ] 2 [-1,1]^2 [1,1]2映射到矩形 [ − 0.5 , n x − 0.5 ] × [ − 0.5 , n y − 0.5 ] [-0.5,n_x-0.5]\times[-0.5,n_y-0.5] [0.5,nx0.5]×[0.5,ny0.5] 1

根据我们上文的窗口转换可以推导出:
[ x s c r e e n y s c r e e n z s c r e e n 1 ] = [ n x 2 0 0 n x − 1 2 0 n y 2 0 n y − 1 2 0 0 1 0 0 0 0 1 ] [ x c a n o n i c a l y c a n o n i c a l z c a n o n i c a l 1 ] \begin{bmatrix} x_{screen}\\ y_{screen}\\ z_{screen}\\ 1 \end{bmatrix}= \begin{bmatrix} \frac{n_x}{2}&0&0&\frac{n_x-1}{2}\\ 0& \frac{n_y}{2}&0&\frac{n_y-1}{2}\\ 0&0&1&0\\ 0&0&0&1\\ \end{bmatrix} \begin{bmatrix} x_{canonical}\\ y_{canonical}\\ z_{canonical}\\ 1 \end{bmatrix} xscreenyscreenzscreen1=2nx00002ny0000102nx12ny101xcanonicalycanonicalzcanonical1
注意这里我们保留了z值 即 z s c r e e n = z c a n o n i c a l z_{screen}=z_{canonical} zscreen=zcanonical. z值可以用于比较物体的远近.
由此我们得到了屏幕映射矩阵:
M v p = [ n x 2 0 0 n x − 1 2 0 n y 2 0 n y − 1 2 0 0 1 0 0 0 0 1 ] M_{vp}= \begin{bmatrix} \frac{n_x}{2}&0&0&\frac{n_x-1}{2}\\ 0& \frac{n_y}{2}&0&\frac{n_y-1}{2}\\ 0&0&1&0\\ 0&0&0&1\\ \end{bmatrix} Mvp=2nx00002ny0000102nx12ny101
注意,这里的vp代表的是viewport.

小结

至此,我们知道了给定一个小立方体如何投射到屏幕上. 这里我们忽略了z值,真正渲染的时候z是用来判定物品远近的. 这点在后续的博文中将会更一进步介绍.

正交映射(Orth projection transformation)

在上文中,我们已知如何把小立方体映射到屏幕上. 现在我们把难度升级,假设我们想要渲染一个长方体如下图所示:
在这里插入图片描述
由于我们已知如何把小立方体映射到屏幕上,所以如果我们可以把长方体映射到小立方体上即可.
[ l , r ] × [ b , t ] × [ n , f ] → [ − 1 , 1 ] 3 [l,r]\times[b,t]\times[n,f] \rightarrow [-1,1]^3 [l,r]×[b,t]×[n,f][1,1]3.
利用窗口转换可以得出:
M o r t h = [ 2 r − l 0 0 − r + l r − l 0 2 t − b 0 − t + b t − b 0 0 2 n − f − n + f n − f 0 0 0 1 ] M_{orth}= \begin{bmatrix} \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}{n-f}& -\frac{n+f}{n-f} \\ 0&0&0&1\\ \end{bmatrix} Morth=rl20000tb20000nf20rlr+ltbt+bnfn+f1

小结

现在假设给定长方体内的坐标(x,y,z,1). 我们现在可以获得如下公式:
[ x p i x e l y p i x e l z c a n o n i c a l 1 ] = ( M v p ) ( M o r t h ) [ x y z 1 ] \begin{bmatrix} x_{pixel}\\y_{pixel}\\z_{canonical}\\1 \end{bmatrix}= (M_{vp})(M_{orth}) \begin{bmatrix} x\\y\\z\\1 \end{bmatrix} xpixelypixelzcanonical1=(Mvp)(Morth)xyz1

观察变换(CameraSpace transformation)

在上述空间转换中,我们都假定了摄像机朝向为-z,摄像机顶朝向为+y.
假定摄像机的位置在世界坐标为E,三个坐标轴分别为u,v,w.
在这里插入图片描述
参考坐标空间转换,可以得到从世界坐标系一点到摄像机坐标系的映射为:
M c a m = [ u v w e 0 0 0 1 ] − 1 M_{cam}=\begin{bmatrix} u&v&w&e\\ 0&0&0&1\\ \end{bmatrix}^{-1} Mcam=[u0v0w0e1]1
现在我们来思考这四个向量如何获得:

  1. e为摄像机在世界空间的坐标.
  2. w为摄像机的反向单位向量. 假定我们设g为从摄像机到观察点的向量.
    w = − g ∣ ∣ g ∣ ∣ w=-\frac{g}{||g||} w=gg
  3. 然后任意指定u或者v后, 剩下的可以通过w和其叉积求出.

接口考虑

多数情况下,摄像机初始化时的摆放是正方向的. 意味着摄像机是摆正状态,不会饶观察方向旋转.
在这种情况下,我们可以指定一个view-up向量t, 通常情况下选定(0,1,0).
其中v,t,g,w均在同一平面上.此时可以得出下列公式:
w = − g ∣ ∣ g ∣ ∣ w=-\frac{g}{||g||} w=gg
u = t × w ∣ ∣ t × w ∣ ∣ u=\frac{t\times w}{||t\times w||} u=t×wt×w
v = w × u v=w \times u v=w×u
这里我们不直接使用t来当做v是由于t并不一定垂直于w.
但是由于t,v,w同一平面,所以t和w叉乘的结果会垂直于t和w所在的平面,也即v所在的平面. 这代表了u垂直于v和w.
这样在摆正摄像机的前提下,我们只用指定一个暗示方向t即可自动算出v和u了.

小结

综上,我们新获得了一个 M c a m M_{cam} Mcam矩阵. 结合上文,从世界空间到屏幕空间的矩阵如下:
M w o r l d → p i x l e = M v p M o r t h M c a m M_{world\rightarrow pixle}=M_{vp}M_{orth}M_{cam} Mworldpixle=MvpMorthMcam

透视投影(Projective Transformation)

不同于正交投影,透视投影是模拟人类眼睛的一种投影方式. 即越远的物体显示的越小,如下图所示:
在这里插入图片描述
上图红色位置为摄像机,白色竖线为屏幕,可以看到离屏幕比较近的绿色立方体映射的位置比蓝色要高.
具体的计算过程看下图分析:
在这里插入图片描述
这里做如下假定:
摄像机位置位于原点,朝向为-z.
那么根据相似三角形,我们可以得到如下等式:
y s y = d − z \frac{y_s}{y}=\frac{d}{-z} yys=zd

y s = d − z × y {y_s}=\frac{d}{-z}\times y ys=zd×y
用矩阵的表达形式:
y s = [ d − z 0 0 1 ] × [ y 1 ] y_s=\begin{bmatrix} \frac{d}{-z}&0\\ 0&1 \end{bmatrix} \times \begin{bmatrix} y\\ 1 \end{bmatrix} ys=[zd001]×[y1]
使矩阵变为常量:
y s = [ − d 0 0 1 ] × [ y z 1 ] y_s=\begin{bmatrix} -d&0\\ 0&1 \end{bmatrix} \times \begin{bmatrix} \frac{y}{z}\\ 1 \end{bmatrix} ys=[d001]×[zy1]
设近平面为n,则n=-d,于是我们有以下:
y s = [ n 0 0 1 ] × [ y z 1 ] = [ n 0 0 1 ] × [ y z ] y_s=\begin{bmatrix} n&0\\ 0&1 \end{bmatrix} \times \begin{bmatrix} \frac{y}{z}\\ 1 \end{bmatrix} = \begin{bmatrix} n&0\\ 0&1 \end{bmatrix} \times \begin{bmatrix} y\\ z \end{bmatrix} ys=[n001]×[zy1]=[n001]×[yz]
x坐标同理获得,于是得到如下矩阵:
[ x s y s z s 1 ] = [ n 0 0 0 0 n 0 0 . . . . . . . . . . . . 0 0 1 0 ] × [ x y z 1 ] = [ n x n y . . . z ] = [ n x z n y z . . . 1 ] \begin{bmatrix} x_s\\ y_s\\ z_s\\ 1\\ \end{bmatrix}= \begin{bmatrix} n&0&0&0\\ 0&n&0&0\\ ...&...&...&...\\ 0&0&1&0\\ \end{bmatrix} \times \begin{bmatrix} x\\ y\\ z\\ 1\\ \end{bmatrix} = \begin{bmatrix} nx\\ ny\\ ...\\ z\\ \end{bmatrix} = \begin{bmatrix} \frac{nx}{z}\\ \frac{ny}{z}\\ ...\\ 1\\ \end{bmatrix} xsyszs1=n0...00n...000...100...0×xyz1=nxny...z=znxzny...1
综上,我们已经获得了x和y的处理方案.接下来我们看下z值如何处理.
第一种方案就是和正交投影一样,我们不让z值改变.这样我们就得到了一个长方体.然后我们再继续做正交投影即可.
我们假设矩阵的第三行分别为a,b,c,d.
于是 z s = a x + b y + c z + d z z_s=\frac{ ax+by+cz+d}{z} zs=zax+by+cz+d
由于x和y坐标与 z s z_s zs是无关的.所以a和b代入0:
z s = c z + d z = c + d z z_s=\frac{cz+d}{z}=c+\frac{d}{z} zs=zcz+d=c+zd
由于我们想保留z值,那么可以尝试解决这个等式. 分别代入近平面和远平面:
代入近平面 z s = z = n = c + d n z_s=z=n=c+\frac{d}{n} zs=z=n=c+nd
代入远平面 z s = z = f = c + d f z_s=z=f=c+\frac{d}{f} zs=z=f=c+fd
把n和f当已知值,c和d当未知值,即二元一次方程组.解得:
c = n + f d = − f n c=n+f \quad d=-fn c=n+fd=fn
让我们把c和d代入原等式:
z s = c + d z = ( n + f ) + − f n z z_s=c+\frac{d}{z}=(n+f)+\frac{-fn}{z} zs=c+zd=(n+f)+zfn
这里可以看出 z s z_s zs和z无法成为线性关系.其中-fn<0,z<0, − f n z &gt; 0 \frac{-fn}{z}&gt;0 zfn>0.
我们缓慢的让z变小,即向摄像机朝向移动,则 − f n z \frac{-fn}{z} zfn减小, z s z_s zs减小.
由此可知:
z s z_s zs最大为n,此时 z s z_s zs位于近平面.
朝着摄像机朝向移动, z s z_s zs减小.
z s z_s zs最小为f,此时 z s z_s zs位于远平面.
这样随无法保留z值,但是z值得顺序得以保留.代入我们计算的c和d,我们得到:
P = [ n 0 0 0 0 n 0 0 0 0 n + f − f n 0 0 1 0 ] P= \begin{bmatrix} n&amp;0&amp;0&amp;0\\ 0&amp;n&amp;0&amp;0\\ 0&amp;0&amp;n+f&amp;-fn\\ 0&amp;0&amp;1&amp;0\\ \end{bmatrix} P=n0000n0000n+f100fn0
注意此时我们得到的矩阵是从摄像机空间到长方体的映射. 而投影则是把摄像机空间映射到小立方体即NDC上.
于是 我们得到
M p e r = M o r t h P M_{per}=M_{orth}P Mper=MorthP
让我们把上文推导出的 M o r t h M_{orth} Morth代入:
M p e r = [ 2 r − l 0 0 − r + l r − l 0 2 t − b 0 − t + b t − b 0 0 2 n − f − n + f n − f 0 0 0 1 ] × [ n 0 0 0 0 n 0 0 0 0 n + f − f n 0 0 1 0 ] M_{per}= \begin{bmatrix} \frac{2}{r-l}&amp;0&amp;0&amp; -\frac{r+l}{r-l}\\ 0&amp; \frac{2}{t-b}&amp;0&amp; -\frac{t+b}{t-b}\\ 0&amp;0&amp;\frac{2}{n-f}&amp; -\frac{n+f}{n-f} \\ 0&amp;0&amp;0&amp;1\\ \end{bmatrix} \times \begin{bmatrix} n&amp;0&amp;0&amp;0\\ 0&amp;n&amp;0&amp;0\\ 0&amp;0&amp;n+f&amp;-fn\\ 0&amp;0&amp;1&amp;0\\ \end{bmatrix} Mper=rl20000tb20000nf20rlr+ltbt+bnfn+f1×n0000n0000n+f100fn0
M p e r = [ 2 n r − l 0 l + r l − r 0 0 2 n t − b b + t b − t 0 0 0 f + n n − f 2 f n f − n 0 0 1 0 ] M_{per}= \begin{bmatrix} \frac{2n}{r-l}&amp;0&amp; \frac{l+r}{l-r}&amp; 0 \\ 0&amp; \frac{2n}{t-b}&amp; \frac{b+t}{b-t}&amp; 0 \\ 0&amp;0&amp;\frac{f+n}{n-f}&amp; \frac{2fn}{f-n} \\ 0&amp;0&amp;1&amp;0\\ \end{bmatrix} Mper=rl2n0000tb2n00lrl+rbtb+tnff+n100fn2fn0

额外

模型变换 (Modelling transformation)

模型变换其实就是简单的坐标系变换.可以参考坐标空间转换

裁剪空间(ClipSpace)

首先明确一点,裁剪空间是在NDC的前一步发生的.也就是映射到小立方体之前.
对于非透视投影:
M m o d e l → w o r l d → c a m e r a → o r t h M_{model\rightarrow world \rightarrow camera \rightarrow orth} Mmodelworldcameraorth 裁剪后 除以w到NDC.
对于透视投影:
M m o d e l → w o r l d → c a m e r a → p e r s M_{model\rightarrow world \rightarrow camera \rightarrow pers} Mmodelworldcamerapers 裁剪后 除以w到NDC.
在上述描述中裁剪的所在位置就是ClipSpace.
这里面所有的坐标都要与w进行比较,只有大于等于-w并且小于等于w时才可以进入小立方体. 注意这里的w对于每一个点都是不一样的.
这里我们可以反向理解,只有在小立方体(NDC)的点才会被渲染,所以在NDC中只有满足大于等于-1小于等于1的点会被渲染. 那么在除之前 自然只有大于等于-w且小于等于w才能被渲染.

Z-fighting

假设 z e z_e ze代表的是相机空间的z值, z n z_n zn代表透视投影中正交投影前的z值.
我们上文推导中:
z n = c + d z e = ( n + f ) + − f n z e z_n=c+\frac{d}{z_e}=(n+f)+\frac{-fn}{z_e} zn=c+zed=(n+f)+zefn
函数图像2为下图所示:
在这里插入图片描述
可以发现当近平面和远平面距离很远的时候, z e z_e ze及时发生了较大的改变,对于 z n z_n zn来讲,只是一点点的变化. 那么当精度不够时,就会产生所谓的Z-fighting现象.

总结

每个空间转换单独来理解都是比较好理解的. 比较难理解的透视投影也可以拆成先映射到正交投影再映射到NDC中. 对于渲染中的空间转换相关知识看了很多资料总是一知半解, 主要原因在于有些知识囫囵吞枣,另外没有亲自动手推导过.

好比摄像机的Up Vector, 本来以为自己很清楚了,但是在写blog的过程中发现.如果绕着摄像机观察方向旋转,此时不可以简单的指定Vector.up为(0,1,0).


  1. 参考上文像素坐标约定 ↩︎

  2. 图片来自 songho教程 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值