3D渲染管线中的坐标变换

3D物体被渲染到屏幕之前,会经历以下的坐标变换:

  • 局部坐标 Local Coordinates
  • 世界坐标 World Coordinates
  • 相机坐标 Camera Coordinates
  • 透视坐标 Perspective Coordinates
  • 屏幕坐标 Screen Coordinates

在不考虑光照计算、着色处理和纹理映射,只考虑几何变换的情况下,3D渲染管线中的坐标变换流程如下:
3D渲染管线中的坐标变换_第1张图片
该变换流程,将3D模型的局部坐标,变换到屏幕坐标。
本文先不考虑物体消除、背面消除和物体空间的剪裁。


一、局部坐标

局部坐标也叫模型坐标,使用局部坐标,可以将模型平移到世界坐标中的实际位置。
可以将物体的中心当做局部坐标系的原点,如下图所示的立方体:
3D渲染管线中的坐标变换_第2张图片
立方体边长为10个单位,中心坐标为(0,0,0),各顶点在局部坐标系中的坐标如下:

Vertex 0: (10,10,10)		Vertex 1: (-10,10,10)
Vertex 2: (-10,10,-10)		Vertex 3: (10,10,-10)
Vertex 4: (10,-10,10)		Vertex 5: (-10,-10,10)
Vertex 6: (-10,-10,-10)		Vertex 7: (10,-10,-10)

也可以将其他位置作为局部坐标系的原点,例如下图所示的机器人手臂:
3D渲染管线中的坐标变换_第3张图片
可以将手臂的一端作为局部坐标系的原点,从而实现旋转摆动手臂的动作。

我们可以将旋转缩放放到局部坐标变换中完成。


二、世界坐标

将局部坐标变换到世界坐标,只需将物体平移到世界坐标的某个位置即可。
假设游戏的世界大小为1000x1000x1000,且要将模型平移到世界空间中的位置 ( x w , y w , z w ) (x_w, y_w, z_w) (xw,yw,zw)

3D渲染管线中的坐标变换_第4张图片

则有平移矩阵形式如下:
T m w = [ 1 0 0 0 0 1 0 0 0 0 1 0 x w y w z w 1 ] {\bf T_{mw}} =\left[ \begin{matrix} 1&0&0&0\\\\ 0&1&0&0\\\\ 0&0&1&0\\\\ x_w&y_w& z_w &1\\\\ \end{matrix} \right] Tmw=100xw010yw001zw0001

将向量和矩阵相乘,可以实现模型坐标到世界坐标的平移,矩阵运算如下:

V m T m w = [ x m y m z m 1 ] T [ 1 0 0 0 0 1 0 0 0 0 1 0 x w y w z w 1 ] = [ x m + x w y m + y w z m + z w 1 ] T {\bf V_mT_{mw}} =\left[\begin{matrix} x_m\\\\ y_m\\\\ z_m\\\\ 1\end{matrix}\right]^ \mathrm{ T } \left[ \begin{matrix} 1&0&0&0\\\\ 0&1&0&0\\\\ 0&0&1&0\\\\ x_w&y_w& z_w &1\\\\ \end{matrix} \right] =\left[\begin{matrix} x_m+x_w\\\\ y_m+y_w\\\\ z_m+z_w\\\\ 1\end{matrix}\right]^ \mathrm{ T } VmTmw=xmymzm1T100xw010yw001zw0001=xm+xwym+ywzm+zw1T


三、相机坐标

相机的参数:

  • 相机在世界坐标中的位置
  • 相机的方向
  • 视野 FOV
  • 远剪裁面近剪裁面 —— 只有位于远近剪裁面之间的物体才可见,其他物体都不可见
  • 视平面/投影面 —— 3D图像会投影到这个平面
    3D渲染管线中的坐标变换_第5张图片

将世界坐标变换为相机坐标:
对世界中的物体进行变换,使其位置是相对于相机的。因此,要人为地将物体从世界坐标系变换到相机坐标系,使得相机位于世界坐标系的原点,并指向+Z轴方向。

在图形学中,物体的运动是相对的,要移动相机,使得相机位于世界坐标系的原点,并指向+Z轴方向,只需相应移动所有的物体。这种变换分两步完成:先平移,后旋转

3D渲染管线中的坐标变换_第6张图片

A:平移前,物体的位置为 P o b j = ( w o r l d x , w o r l d y , w o r l d z ) P_{obj}=(world_x,world_y,world_z) Pobj=(worldx,worldy,worldz),相机的位置为 P c a m = ( c a m x , c a m y , c a m z ) P_{cam}=(cam_x,cam_y,cam_z) Pcam=(camx,camy,camz)
B:平移后,物体的位置为 P o b j − P c a m P_{obj} - P_{cam} PobjPcam
C:旋转后,物体的世界坐标变换到了相机坐标。

平移矩阵最下面一行是相机位置求反:
T c a m − 1 = [ 1 0 0 0 0 1 0 0 0 0 1 0 − c a m x − c a m y − c a m z 1 ] {\bf T_{cam}}^{-1} = \left[ \begin{matrix} 1&0&0&0\\\\ 0&1&0&0\\\\ 0&0&1&0\\\\ -cam_x&-cam_y&-cam_z &1\\\\ \end{matrix} \right] Tcam1=100camx010camy001camz0001

绕三个轴旋转的旋转矩阵,旋转角度也要取反:
R c a m x − 1 = [ 1 0 0 0 0 cos ⁡ ( − θ x ) sin ⁡ ( − θ x ) 0 0 − sin ⁡ ( − θ x ) cos ⁡ ( − θ x ) 0 0 0 0 1 ] = [ 1 0 0 0 0 cos ⁡ ( θ x ) − sin ⁡ ( θ x ) 0 0 sin ⁡ ( θ x ) cos ⁡ ( θ x ) 0 0 0 0 1 ] {\bf R_{camx}}^{-1} = \left[ \begin{matrix} 1&0&0&0\\\\ 0&\cos(-\theta_x)&\sin(-\theta_x)&0\\\\ 0&-\sin(-\theta_x)&\cos(-\theta_x)&0\\\\ 0&0&0&1\\\\ \end{matrix} \right] =\left[ \begin{matrix} 1&0&0&0\\\\ 0&\cos(\theta_x)&-\sin(\theta_x)&0\\\\ 0&\sin(\theta_x)&\cos(\theta_x)&0\\\\ 0&0&0&1\\\\ \end{matrix} \right] Rcamx1=10000cos(θx)sin(θx)00sin(θx)cos(θx)00001=10000cos(θx)sin(θx)00sin(θx)cos(θx)00001

R c a m y − 1 = [ cos ⁡ ( − θ y ) 0 − sin ⁡ ( − θ y ) 0 0 1 0 0 sin ⁡ ( − θ y ) 0 cos ⁡ ( − θ y ) 0 0 0 0 1 ] = [ cos ⁡ ( θ y ) 0 sin ⁡ ( θ y ) 0 0 1 0 0 − sin ⁡ ( θ y ) 0 cos ⁡ ( θ y ) 0 0 0 0 1 ] {\bf R_{camy}}^{-1} = \left[ \begin{matrix} \cos(-\theta_y)&0&-\sin(-\theta_y)&0\\\\ 0&1&0&0\\\\ \sin(-\theta_y)&0&\cos(-\theta_y)&0\\\\ 0&0&0&1\\\\ \end{matrix} \right]= \left[ \begin{matrix} \cos(\theta_y)&0&\sin(\theta_y)&0\\\\ 0&1&0&0\\\\ -\sin(\theta_y)&0&\cos(\theta_y)&0\\\\ 0&0&0&1\\\\ \end{matrix} \right] Rcamy1=cos(θy)0sin(θy)00100sin(θy)0cos(θy)00001=cos(θy)0sin(θy)00100sin(θy)0cos(θy)00001

R c a m z − 1 = [ cos ⁡ ( − θ z ) sin ⁡ ( − θ z ) 0 0 − sin ⁡ ( − θ z ) cos ⁡ ( − θ z ) 0 0 0 0 1 0 0 0 0 1 ] = [ cos ⁡ ( θ z ) − sin ⁡ ( θ z ) 0 0 sin ⁡ ( θ z ) cos ⁡ ( θ z ) 0 0 0 0 1 0 0 0 0 1 ] {\bf R_{camz}}^{-1} = \left[ \begin{matrix} \cos(-\theta_z)&\sin(-\theta_z)&0&0\\\\ -\sin(-\theta_z)&\cos(-\theta_z)&0&0\\\\ 0&0&1&0\\\\ 0&0&0&1\\\\ \end{matrix} \right]= \left[ \begin{matrix} \cos(\theta_z)&-\sin(\theta_z)&0&0\\\\ \sin(\theta_z)&\cos(\theta_z)&0&0\\\\ 0&0&1&0\\\\ 0&0&0&1\\\\ \end{matrix} \right] Rcamz1=cos(θz)sin(θz)00sin(θz)cos(θz)0000100001=cos(θz)sin(θz)00sin(θz)cos(θz)0000100001
上述三个旋转矩阵的推导可参考:3D旋转矩阵的推导
综合上述四个矩阵,世界坐标到相机坐标的变换矩阵为:
T w c = T c a m − 1 R c a m x − 1 R c a m y − 1 R c a m z − 1 {\bf T_{wc}} = {\bf T_{cam}}^{-1}{\bf R_{camx}}^{-1}{\bf R_{camy}}^{-1}{\bf R_{camz}}^{-1} Twc=Tcam1Rcamx1Rcamy1Rcamz1


四、透视坐标

透视变换(投影变换):从相机坐标到透视坐标的变换。本质上就是做一个透视除法,实现近大远小的效果。
视距 d d d:视平面和投影点(视点)之间的距离。
视平面(viewplane):
3D渲染管线中的坐标变换_第7张图片

视距计算公式:
d = W / 2 × tan ⁡ ( θ h / 2 ) d = W/2\times \tan (\theta_h/2) d=W/2×tan(θh/2)

透视变换:将所有物体投影到视平面上。给定视距 d d d,可以计算出物体上的点和视点的连线与视平面的交点

3D渲染管线中的坐标变换_第8张图片

根据三角形相似,可得透视坐标:
{ X p e r = d x 0 / z 0 Y p e r = d y 0 / z 0 \begin{cases} X_{per} = dx_0/z_0 \\ Y_{per} = dy_0/z_0 \\ \end{cases} {Xper=dx0/z0Yper=dy0/z0


五、屏幕坐标

屏幕变换

视口(viewport) = 屏幕 (screen)= 光栅化窗口

屏幕变换:将视平面坐标转换到屏幕坐标。

屏幕的原点是(0,0),位于左上角,屏幕宽高分别为 W s W_s Ws H s H_s Hs,屏幕大小为 W s × H s W_s \times H_s Ws×Hs,宽高比 a r = W s / H s ar = W_s / H_s ar=Ws/Hs,且y轴被反转,如下图所示:
3D渲染管线中的坐标变换_第9张图片
1.视野为90度且视距为1的情况
在这种情况下,透视空间中,视平面的坐标在每个轴上被归一化为-1到1。
X p e r X_{per} Xper(从-1到1) 转换到 X s c r e e n X_{screen} Xscreen (从0到 W s − 1 W_s-1 Ws1)
Y p e r Y_{per} Yper(从-1到1) 转换到 Y s c r e e n Y_{screen} Yscreen (从0到 H s − 1 H_s-1 Hs1)

{ X s c r e e n = ( X p e r + 1 ) / 2 × ( W s − 1 ) Y s c r e e n = ( Y − 1 ) − ( Y p e r + 1 ) / 2 × ( H s − 1 ) \begin{cases} X_{screen} = (X_{per}+1)/2 \times (W_s-1) \\ Y_{screen} = (Y-1)-(Y_{per}+1)/2 \times (H_s-1) \\ \end{cases} {Xscreen=(Xper+1)/2×(Ws1)Yscreen=(Y1)(Yper+1)/2×(Hs1)

α = ( W s − 1 ) / 2 \alpha =(W_s-1)/2 α=(Ws1)/2 β = ( H s − 1 ) / 2 \beta=(H_s-1)/2 β=(Hs1)/2,则有
{ X s c r e e n = α + α X p e r Y s c r e e n = β − β Y p e r \begin{cases} X_{screen} =\alpha+ \alpha X_{per} \\ Y_{screen} = \beta -\beta Y_{per} \\ \end{cases} {Xscreen=α+αXperYscreen=ββYper
其中, ( α , β ) (\alpha,\beta) (α,β)是屏幕中心坐标。

2.一般情况:任意视野和任意视距的情况
在任意视野和任意视距的情况下,我们使用公式 d = W / 2 × tan ⁡ ( θ h / 2 ) d = W/2\times \tan (\theta_h/2) d=W/2×tan(θh/2)来计算视距,因为没有被归一化,同样令 α = ( W s − 1 ) / 2 \alpha =(W_s-1)/2 α=(Ws1)/2 β = ( H s − 1 ) / 2 \beta=(H_s-1)/2 β=(Hs1)/2,则有
{ X s c r e e n = α + X p e r Y s c r e e n = β − Y p e r \begin{cases} X_{screen} =\alpha+ X_{per} \\ Y_{screen} = \beta -Y_{per} \\ \end{cases} {Xscreen=α+XperYscreen=βYper


参考资料:

  1. 《3D游戏编程大师技巧》 p328-362

你可能感兴趣的:(3D,渲染,管线,坐标,变换,计算机图形学)