参考:Rasterization

简述

  光栅化是将屏幕空间中的几何图元(通常为三角形)离散化为像素片段,并为每个片段计算相关插值属性的过程。

基本流程

  一个基本的光栅化器可按以下方式工作(以类似 OpenGL 的流程为例):

Edge函数

  Edge 函数基于二维向量的叉乘符号,用于判断一点相对于一条有向边的位置关系。在二维空间中,给定向量 $a = (x_a, y_a)$,$b = (x_b, y_b)$,其叉乘在 $z$ 轴方向上的标量形式定义为: $a \times b={x_a}{y_b}-{y_a}{x_b}$,该结果是有符号的,其符号表示 $b$ 位于 $a$ 的左侧或右侧。几何上,该值等于由两向量构成的平行四边形的有符号面积。
  在光栅化中,通过对三角形三条有向边分别计算 Edge 函数,可以判断屏幕空间中的一点是否位于三角形内部,并可进一步用于计算重心坐标。

rasterization
图 1:白色区域内包含的点全部位于三角形所有三个边的右侧。

重心坐标

  重心坐标 $(\lambda_0,\lambda_1,\lambda_2)$ 是三个实数组成的元组,对于处于同一坐标系的三角形顶点$V_0$、$V_1$、$V_2$ 及点 $P$,重心坐标描述了点 $P$ 相对于三角形顶点的线性组合权重,$P$ 是三点的加权求和 $\lambda_0 \times V_0+\lambda_1 \times V_1+\lambda_2 \times V_2$。对于位于三角形内部或边界上的点,有 $\lambda_0 + \lambda_1 + \lambda_2 = 1$ 且 $\lambda_i \geq 0$
  重心坐标可用于在 2D 屏幕空间对顶点进行插值。对于经过透视投影映射到屏幕空间的顶点,由于插值在屏幕空间是仿射进行的,可以对原始顶点 z 坐标的倒数及相应的顶点参数进行线性插值,从而实现透视正确的插值结果。
  摄像机空间的三角形 $V_0V_1V_2$ 和其上一点 $P$ 投影到屏幕空间,得到 $V_0'V_1'V_2'$ 和 $P'$,设点 $P'$ 关于屏幕空间三角形 $V_0'V_1'V_2'$ 的重心坐标为 $(\lambda_0,\lambda_1,\lambda_2)$,则有:

$$Z_p = \frac{1}{\frac{\lambda_0}{Z_0} + \frac{\lambda_1}{Z_1} + \frac{\lambda_2}{Z_2}}$$

  同时顶点属性 $C$ 也可以按相同方式进行透视矫正插值:

$$C_p = Z_p \times \left(\frac{\lambda_0 \times C_0}{Z_0} + \frac{\lambda_1 \times C_1}{Z_1} + \frac{\lambda_2 \times C_2}{Z_2} \right)$$

  在二维平面中,点 $P$ 相对于三角形顶点 $V_i$ 的重心坐标权重 $\lambda_i$,定义为点 $P$ 与顶点 $V_i$ 对边构成的子三角形的有符号面积,与原三角形有符号面积之比。

barycentric
图 2:重心坐标

左上规则

  左上规则(Top-Left Rule)是一种像素覆盖判定规则,用于在光栅化阶段解决共享边三角形的像素归属问题,避免重复覆盖或遗漏:

  通过左上规则,可以保证任意一个像素在共享边界处最多只被一个三角形覆盖,从而保证光栅化结果的一致性和确定性。

Z 缓冲

  Z 缓冲区是一个与帧缓冲大小相同的二维浮点数组,用于记录每个像素的深度,从而解决三角形重叠和可见性问题。在光栅化过程中,对于每个片段:

  在渲染完成后,深度缓冲区保存了场景中每个像素可见三角形的最小深度,从而形成可用于遮挡测试的深度图。

抗锯齿

  锯齿是由于光栅化过程中像素离散化造成的阶梯状边缘伪影。为减少这种视觉效果,需要采用抗锯齿(AA)技术。
  一种常用的基于采样的抗锯齿方法是多重采样(Multisample / Supersampling):

其中 $N$ 通常是 2 的幂(2、4、8 等),以平衡抗锯齿效果与性能开销。
这种方法能显著降低锯齿,但需要对每个像素进行多次光栅化和颜色计算,因此性能开销较大。

透视投影矩阵

  透视投影矩阵变换摄像机空间中的坐标,将处于视锥体内处于近裁剪平面和远裁剪平面之间的 $x$、$y$、$z$ 坐标映射到 $[-1,1]$。设视锥体垂直视场的角度为 $Fov$,水平视场角度与垂直视场角度比值为为 $a$,近裁剪平面距离为 $Z_n$,远裁剪平面距离为 $Z_f$,则透视投影矩阵为:

$$\begin{bmatrix} \frac{1}{a \times \tan{(Fov \div 2)}} & 0 & 0 & 0 \\ 0 & \frac{1}{\tan{(Fov \div 2)}} & 0 & 0 \\ 0 & 0 & \frac{ Z_n + Z_f}{Z_n - Z_f } & \frac{2 \times Z_n \times Z_f}{Z_n - Z_f} \\ 0 & 0 & -1 & 0 \end{bmatrix}$$

投影 x、y:

$$\begin{align*} \frac{1}{a \times \tan{(Fov \div 2)}} \\\ \frac{1}{\tan{(Fov \div 2)}} \end{align*}$$

前两行系数用于将摄像机空间的 $x$、$y$ 映射到裁剪空间。

remap_point
图 2:$\theta = 45°$,$P'.y = \frac{P.y}{\tan{\delta}}$

投影 z:
  在透视投影中,需要将摄像机空间的 z 坐标映射到裁剪空间 $[-1, 1]$ 以便进行透视除法和深度缓冲。
  设透视投影矩阵第三行元素分别为 $a$ 和 $b$,第四行第三列为 -1,则投影后裁剪空间的 z 分量为:

$$z_c = a z + b, \quad w_c = -z$$

  为了满足裁剪平面的边界条件,需要:

$$\begin{cases} z = -Z_n \Rightarrow z_{ndc} = z_c / w_c = -1 & \text{(近裁剪平面)} \\[2mm] z = -Z_f \Rightarrow z_{ndc} = z_c / w_c = 1 & \text{(远裁剪平面)} \end{cases}$$

  代入 $z_{ndc} = z_c / w_c = (a z + b)/(-z) = -a - \frac{b}{z}$,得到方程组:

$$\begin{cases} -a - \dfrac{b}{-Z_n} = -1 \\[1mm] -a - \dfrac{b}{-Z_f} = 1 \end{cases}$$

  解得:

$$a = \frac{Z_n + Z_f}{Z_n - Z_f}, \quad b = \frac{2 Z_n Z_f}{Z_n - Z_f}$$

第四行第三列为 -1,保证投影后进行透视除法时 $w = -z$,从而保持深度正向关系。