Skip to content

Lecture 5: Rasterization 1(Triangles)

Perspective Projection

这个变换使用的矩阵是上节课提到的投影矩阵 (Projection Matrix)。它的作用是将不规则的视锥体空间(即摄像机视野),扭曲成一个非常规整的标准立方体 (Canonical View Volume / Clip Space),这个立方体的xyz坐标范围通常都是 [-1, 1]。

\[ \text{Aspect Ratio} = \frac{\text{Width}}{\text{Height}} \]
\[ \tan(fovY/2) = \frac{\text{Height}/2}{\text{Near}} \]

MVP:model-View-Projection(模型-视图-投影)

Canonical Cube to Screen

光栅化的过程是把图形转换为像素的过程。

像素\((x, y)\)的中心在\((x + 0.5, y + 0.5)\)处。屏幕显示范围从\((0, 0)\)\((W, H)\),其中\(W\)是宽度,\(H\)是高度。

Viewport变换将标准立方体[-1, 1]映射到屏幕坐标系,其使用的矩阵为:

\[ M_{viewport} = \begin{bmatrix}\frac{W}{2} & 0 & 0 & \frac{W}{2} \\0 & \frac{H}{2} & 0 & \frac{H}{2} \\0 & 0 & 1 & 0 \\0 & 0 & 0 & 1\end{bmatrix} \]

其几何意义是先将标准立方体[-1, 1]映射到[-W/2, W/2]和[-H/2, H/2],然后平移到屏幕坐标系。

Triangles

三角形是计算机图形学中最基本的图元。它由三个顶点组成,每个顶点都有一个位置和颜色等属性。

采样

采样是将连续的图形数据转换为离散的像素数据的过程。采样可以通过对三角形进行光栅化来实现。

以三角形的采样为例,定义一个函数\(inside\),规定:

\[ inside(tri, x, y) = \begin{cases} 1, & \text{if } (x, y) \text{ is inside the triangle } tri \\ 0, & \text{otherwise} \end{cases} \]

所以光栅化的过程可以表示为:

C++
1
2
3
4
5
for (int x = 0; x < xMax; x++) {
    for (int y = 0; y < yMax; y++) {
        image[x][y] = inside(triangle, x + 0.5, y + 0.5);
    }
}

那么如何判断点\((x, y)\)是否在三角形内呢?可以使用向量叉积法。

叉积法判断点在三角形内

对于三角形的三个顶点\(A\), \(B\), \(C\),可以计算向量\(AB\)\(AC\),以及点P\((x, y)\)到这三个顶点的向量。然后通过叉积判断点是否在三角形内,即:

\[ \text{cross}(AB, AC) \cdot \text{cross}(AB, (x, y) - A) \geq 0 \\ \text{cross}(BC, BA) \cdot \text{cross}(BC, (x, y) - B) \geq 0 \\ \text{cross}(CA, CB) \cdot \text{cross}(CA, (x, y) - C) \geq 0 \]

更简洁的等价方式

在实践中,通常会采用一种更简洁的等价方法。该方法要求首先确定三角形三个顶点A, B, C的环绕顺序(例如,统一为逆时针)。

假设顶点A, B, C是按逆时针顺序排列的,那么一个点P在三角形ABC内部(或边界上)的充分必要条件是:点P必须位于有向线段AB、BC和CA的同一侧(左侧)。这可以通过以下三个叉积的符号来判断:

\[ \text{cross}(AB, AP) \geq 0 \\ \text{cross}(BC, BP) \geq 0 \\ \text{cross}(CA, CP) \geq 0 \]

这里的关键点是:

  • 如果A, B, C是逆时针顺序,那么上述三个叉积都应该大于等于0。
  • 如果A, B, C是顺时针顺序,那么上述三个叉积都应该小于等于0。

为了降低开销,实际判断inside函数时不会将所有点都计算一次,而是会使用一个包围盒(Bounding Box)来快速排除不在三角形内的点。而且可以使用类似行扫描的方式来找到每一行的最小和最大x坐标,从而减少需要检查的点数。