Games101-Homework2

本章内容

本章主要讲述Games101的作业2,涉及光栅化内容。

作业内容

  • [5 分] 正确地提交所有必须的文件,且代码能够编译运行。
  • [20 分] 正确实现三角形栅格化算法。
  • [10 分] 正确测试点是否在三角形内。
  • [10 分] 正确实现 z-buffer 算法, 将三角形按顺序画在屏幕上。
  • [提高项 5 分] 用 super-sampling 处理 Anti-aliasing : 你可能会注意 到,当我们放大图像时,图像边缘会有锯齿感。我们可以用 super-sampling 来解决这个问题,即对每个像素进行 2 * 2 采样,并比较前后的结果 (这里 并不需要考虑像素与像素间的样本复用)。需要注意的点有,对于像素内的每 一个样本都需要维护它自己的深度值,即每一个像素都需要维护一个 sample list。最后,如果你实现正确的话,你得到的三角形不应该有不正常的黑边。

基础部分

实现

需要修改的函数如下:

  • rasterize_triangle(): 执行三角形栅格化算法
  • static bool insideTriangle(): 测试点是否在三角形内。你可以修改此函 数的定义,这意味着,你可以按照自己的方式更新返回类型或函数参数。

rasterize_triangle():

  • 创建三角形的 2 维 bounding box。
  • 遍历此 bounding box 内的所有像素(使用其整数索引)。然后,使用像素中 心的屏幕空间坐标来检查中心点是否在三角形内。
  • 如果在内部,则将其位置处的插值深度值 (interpolated depth value) 与深度 缓冲区 (depth buffer) 中的相应值进行比较。
  • 如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区 (depth buffer),。

static bool insideTriangle():

  • 作该点与三角形三个顶点的向量
  • 按某个方向依次两两向量叉乘
  • 判断上述3个叉乘结果是否同方向,若同方向说明点在三角形内,反之则在三角形外

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();
int x_max, x_min, y_max, y_min;
x_min = MIN(floor(v[0].x()), MIN(floor(v[1].x()), floor(v[2].x())));
x_max = MAX(ceil(v[0].x()), MAX(ceil(v[1].x()), ceil(v[2].x())));
y_min = MIN(floor(v[0].y()), MIN(floor(v[1].y()), floor(v[2].y())));
y_max = MAX(ceil(v[0].y()), MAX(ceil(v[1].y()), ceil(v[2].y())));
// TODO : Find out the bounding box of current triangle.
// iterate through the pixel and find if the current pixel is inside the triangle
for (int x = x_min; x <= x_max; x++) {
for (int y = y_min; y <= y_max; y++) {
if (insideTriangle(x+0.5, y+0.5, t.v)) {
// If so, use the following code to get the interpolated z value.
auto [alpha, beta, gamma] = computeBarycentric2D(x, y, t.v);
float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
float z_interpolated = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
z_interpolated *= w_reciprocal;
// TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
auto index = get_index(x, y);
if (z_interpolated > depth_buf[index] || std::isinf(depth_buf[index])) {
depth_buf[index] = z_interpolated;
set_pixel(Vector3f(x, y, z_interpolated), t.getColor());
}
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
static bool insideTriangle(int x, int y, const Vector3f* _v)
{
// TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]
Vector3f l1 = Vector3f(_v[0].x() - x, _v[0].y() - y, 0);
Vector3f l2 = Vector3f(_v[1].x() - x, _v[1].y() - y, 0);
Vector3f l3 = Vector3f(_v[2].x() - x, _v[2].y() - y, 0);

int flag = (l1.cross(l2).z() > 0) + (l2.cross(l3).z() > 0) + (l3.cross(l1).z() > 0);

return flag == 3 || flag == 0 ? true : false;
}

运行结果

放大图像后,很明显能感受到图像边缘有锯齿感。

提高部分

实现

代码

运行结果

不维护像素内每个样本的深度信息,有不正常的黑边显示。