参考:Rasterization

简述

  光栅化是将 3D 空间三角形投影至 2D 屏幕空间的过程。

基本流程

  一个基本的光栅化器可按以下方式工作:

Edge函数

  此函数只是将两个向量叉乘,笛卡尔坐标向量叉积定义为 $a \times b = \lvert{a} \rvert \lvert{b} \rvert \sin{\theta}$,其中 $\theta$ 是向量间的夹角,由于向量叉乘不满足交换律且结果是有符号,可用于判断一点在向量的左侧或右侧(从向量指向的方向观察),可用于在二维中判断一点是在三角形上还是在三角形外。同时向量叉乘的结果还是向量构成的平行四边形的有符号面积。

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

重心坐标

  重心坐标 $(\lambda_0,\lambda_1,\lambda_2)$ 是三个数组成的元组,可用于表示构成三角形的 $V_0$、$V_1$、$V_2$ 对于坐标系中一点 $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_0 \geq 0, \lambda_1 \geq 0, \lambda_2 \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)$$

  三角形顶点 $V_i$ 关于三角形上点 $P$ 的权重 $B_i$ 是 $P$ 点与 $V_i$ 所在角对边构成的子三角形的有符号面积与大三角形面积之比。

barycentric
图 2:重心坐标

左上规则

  是一种着色规则,用于解决渲染透明片段时,重复渲染共用边造成错误的叠加,其中:

  执行着色时,仅着色处于三角形内部(不在边上)或在顶边或左边的点。

Z 缓冲

  Z 缓冲区(深度缓冲区)是一个二维的浮点型数组,大小与画布大小相同,它是解决三角形重叠问题的方法之一,在绘制任意三角形的片段(像素点)之前:

  在完成所有三角形的绘制后,深度缓冲区储存了场景可见区域到相机距离的图像。

抗锯齿

  锯齿是在三角形的边缘处或纹理中出现的锯齿状边缘,解决方案称为抗锯齿(AA)。一种基于采样的抗锯齿方法是对同一像素进行多次不同位置的采样,像素通常被划分为 $N \times N$ 的网格,其中 $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 \\ 3 & \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$ 坐标在屏幕空间中被映射到 $[-1,1]$,而将视场为 90° 的对称视口内的坐标归一化总是落在此范围内,乘以此值相当于将当前视口内顶点的 $x$、$y$ 变换到视场角为 90° 的视口内。

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

投影 z:
  将视锥体裁剪平面内 z 坐标映射到 $[-1, 1]$ 有如下推导:设矩阵第 3 行 3 列和 3 行 4列 分别为 $a$ 和 $b$,求其值。

$$\begin{align*} 原始坐标:P(x,y,z) \\\ 投影坐标:\big(-\frac{x}{a \times z \times \tan{(Fov \div 2)}}, -\frac{y}{z \times \tan{(Fov \div 2)}}, z'\big) \\\ 齐次坐标:\big(-\frac{x}{a \times z \times \tan{(Fov \div 2)}}, -\frac{y}{z \times \tan{(Fov \div 2)}}, z', 1\big) \\\ 乘以-z:\big(\frac{x}{a \times \tan{(Fov \div 2)}}, \frac{y}{\tan{(Fov \div 2)}}, -z \times z', -z\big) \\\ 其中 a、b 待定:a \times z + b = -z \times z' \\\ 同除 z:-a - \frac{b}{z} = z' \\\ 当 z = - Z_n 时,z' = -1 \Rightarrow -a - \frac{b}{-Z_n} = -1 \\\ 当 z = - Z_f 时,z' = 1 \Rightarrow -a - \frac{b}{-Z_f} = 1 \\\ 解出 a = \frac{ Z_n + Z_f}{Z_n - Z_f },b = \frac{2 \times Z_n \times Z_f}{Z_n - Z_f} \end{align*}$$

由于变换后需要保留原始 z 坐标取负作为 w, 因此第四行第三列为 -1