《OGL dev》Etay Meiri Tutorial 12 - Perspective Projection 笔记

渲染流程:

  1. 将世界空间进行投影变换,变换到Clip Space(裁剪空间)。
  2. vertex shader不改变空间,gl_Position依旧输出到Clip Space。
  3. Clipper进行裁剪,边界的三角形裁剪为0-2个三角形。
  4. 屏幕映射:执行透视除法,将顶点坐标的所有分量都除以w分量,变换到NDC Space(Normalized Device Coordinates)。NDC Space的xyz坐标都处于[-1, 1]区间内。
  5. 屏幕映射:执行视口变换,从NDC Space变换到Screen Space(屏幕空间)。
  6. 光栅化:光栅器依draw call设定的拓扑(一般都是三角形)绘制图元,并进行插值。
  7. 光栅化:光栅器为每一个插值的结果调用fragment shader输出片元。
  8. 光栅化:光栅器对片元进行深度测试等一系列测试,然后绘制到屏幕上。

透视投影变换由以下四个值确定:

  1. aspect ratio(宽高比):作为投影目标的长方形区域的宽与高之间的比值,aspect ratio = screen width / screen height
  2. vertical field of view(垂直视野):yz平面,摄影机张开的角度。
  3. 近Z平面的位置(z坐标):这允许我们剪除离摄影机太近的对象。
  4. 远Z平面的位置(z坐标):这允许我们剪除距离摄影机太远的对象。
  • 隐含:摄影机处于原点,上方向为Y轴正方向,朝向z轴正方向。

推导透视投影矩阵:

  1. 假设vertical field of view角度为a,宽高比为ar,在投影变换前,近Z平面的z坐标为NearZ,远Z平面的z坐标为FarZ。可得:
    1. 近Z平面的y坐标区间为[-NearZ * tan(a / 2), NearZ * tan(a / 2)]。
    2. 近Z平面的x坐标区间为[-ar * NearZ * tan(a / 2), ar * NearZ * tan(a / 2)]。
    3. 远Z平面的y坐标区间为[-FarZ * tan(a / 2), FarZ * tan(a / 2)]。
    4. 远Z平面的x坐标区间为[-ar * FarZ * tan(a / 2), ar * FarZ * tan(a / 2)]。
  2. 透视投影变换将顶点的z坐标写入到w分量,供透视除法使用。
  3. 因为Clip Space除以w分量就得到NDC Space,近Z平面z坐标映射到-1,远Z平面z坐标映射到1。所以Clip Space中,近Z平面的z坐标为-NearZ,远Z平面的z坐标仍为FarZ。
  4. 因为NDC Space中xy坐标的区间也是[-1, 1],所以Clip Space中,近Z平面上xy坐标的区间为[-NearZ, NearZ],远Z平面上xy坐标的区间为[-FarZ, FarZ]。
  5. 综上透视投影变换使得:
    1. x坐标
      1. -ar * NearZ * tan(a / 2)变换到-NearZ。
      2. ar * NearZ * tan(a / 2)变换到NearZ。
      3. -ar * FarZ * tan(a / 2)变换到-FarZ。
      4. ar * FarZ * tan(a / 2)变换到FarZ。
    2. y坐标
      1. -NearZ * tan(a / 2)变换到-NearZ。
      2. NearZ * tan(a / 2)变换到NearZ。
      3. -FarZ * tan(a / 2)变换到-FarZ。
      4. FarZ * tan(a / 2)变换到FarZ。
    3. z坐标
      1. NearZ变换到-NearZ。
      2. FarZ不变。
    4. w坐标:从1变换到z。
  6. 反推透视投影矩阵:
    1. x轴,只进行缩放,缩放值为1artana2\frac{1}{ar \cdot tan\frac{a}{2}}。因此,矩阵第一行为[1artana2\frac{1}{ar \cdot tan\frac{a}{2}}, 0, 0, 0]。
    2. y轴,只进行缩放,缩放值为1tana2\frac{1}{tan\frac{a}{2}}。因此,矩阵第二行为[0, 1tana2\frac{1}{tan\frac{a}{2}}, 0, 0]。
    3. z轴,先缩放后平移。因为区间从[NearZ, FarZ]变换到[-NearZ, FarZ],所以缩放值为FarZ+NearZFarZNearZ\frac{FarZ + NearZ}{FarZ - NearZ}。缩放值后,FarZ变换到FarZ(FarZ+NearZ)FarZNearZ\frac{FarZ \cdot (FarZ + NearZ)}{FarZ - NearZ},要变换到FarZ,需要平移FarZ -FarZ(FarZ+NearZ)FarZNearZ\frac{FarZ \cdot (FarZ + NearZ)}{FarZ - NearZ} = 2FarZNearZFarZNearZ\frac{- 2 \cdot FarZ \cdot NearZ}{FarZ - NearZ}。经验证NearZ缩放后,平移2FarZNearZFarZNearZ\frac{- 2 \cdot FarZ \cdot NearZ}{FarZ - NearZ},结果为-NearZ。因此,平移的值为2FarZNearZFarZNearZ\frac{- 2 \cdot FarZ \cdot NearZ}{FarZ - NearZ},矩阵第三行为[0, 0, FarZ+NearZFarZNearZ\frac{FarZ + NearZ}{FarZ - NearZ}, 2FarZNearZFarZNearZ\frac{- 2 \cdot FarZ \cdot NearZ}{FarZ - NearZ}]。
    4. w分量,从1变换到z。因此,矩阵第四行为[0, 0, 1, 0]。
  7. 组成透视投影矩阵如下:

[1artana200001tana20000NearZ+FarZNearZFarZ2NearZFarZNearZFarZ0010]\begin{bmatrix} \frac{1}{ar \cdot tan\frac{a}{2}} & 0 & 0 & 0 \\ 0 & \frac{1}{tan\frac{a}{2}} & 0 & 0 \\ 0 & 0 & - \frac{NearZ + FarZ}{NearZ - FarZ} & \frac{2 \cdot NearZ \cdot FarZ}{NearZ - FarZ} \\ 0 & 0 & 1 & 0 \end{bmatrix}

Gitalking ...