0%

06 - 光栅化与深度缓冲hwk

1. 作业要求

栅格化一个三角形并且实现深度缓冲。

1.1 实现流程

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

2. 源代码

2.1 insideTriangle()

测试点是否在三角形内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static bool insideTriangle(int x, int y, const Vector3f* _v)
{
Vector3f P(x+0.5f,y+0.5f,1.0f);

const Vector3f& A = _v[0];
const Vector3f& B = _v[1];
const Vector3f& C = _v[2];

Vector3f AB = B - A;
Vector3f BC = C - B;
Vector3f CA = A - C;

Vector3f AP = P - A;
Vector3f BP = P - B;
Vector3f CP = P - C;

float z1 = AB.cross(AP).z();
float z2 = BC.cross(BP).z();
float z3 = CA.cross(CP).z();

return (z1 > 0 && z2 >0 && z3 > 0) || (z1 < 0 && z2 <0 && z3 < 0);
}

2.2 rasterize_triangle()

2.2.1 未抗锯齿

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();

// TODO : Find out the bounding box of current triangle.
// iterate through the pixel and find if the current pixel is inside the triangle

// check triangle coordinates
// for(auto idx : {0, 1, 2})
// {
// std::clog << "pt" << idx << " | " << v[idx].x()
// << " | " << v[idx].y()
// << " | " << v[idx].z()
// << " | " << v[idx].w() << std::endl;
// }

// get bounding box
auto ext_pt_x = std::minmax_element(v.begin(), v.end(),
[](const Eigen::Vector4f& lhs, const Eigen::Vector4f & rhs){
return lhs.x() < rhs.x();
});
auto ext_pt_y = std::minmax_element(v.begin(), v.end(),
[](const Eigen::Vector4f& lhs, const Eigen::Vector4f & rhs){
return lhs.y() < rhs.y();
});
// std::clog << "ext_pt_x: " << ext_pt_x.first->x() << " | " << ext_pt_x.second->x() << std::endl;
// std::clog << "ext_pt_y: " << ext_pt_y.first->y() << " | " << ext_pt_y.second->y() << std::endl;

int min_x = floor(ext_pt_x.first->x());
int max_x = ceil(ext_pt_x.second->x());
int min_y = floor(ext_pt_y.first->y());
int max_y = ceil(ext_pt_y.second->y());

Eigen::Vector3f v3f[3];
for (int idx : {0, 1, 2})
{
v3f[idx] << v[idx].x(), v[idx].y(), 1.0f;
}
// std::transform(std::begin(v), std::end(v), v3f.begin(), [](auto& vec) { return Eigen::Vector3f(vec.x(), vec.y(), vec.z()); });

// 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;

// loop [min_x, max_x] x [min_y, max_y]
for (int x=min_x;x<=max_x;++x)
{
for (int y=min_y;y<=max_y;++y)
{
// no msaa
float x_pos = (float)x + 0.5;
float y_pos = (float)y + 0.5;
auto[alpha, beta, gamma] = computeBarycentric2D(x_pos, y_pos, 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;
int buff_ind = x + y*width;
if (insideTriangle(x_pos, y_pos, v3f) && (-z_interpolated<depth_buf[buff_ind]))
{
set_pixel(Eigen::Vector3f(x, y, 1.0f), t.getColor());
depth_buf[buff_ind] = -z_interpolated;
}
}
}
}

运行结果

screenShot.png

2.2.2 使用MSAA抗锯齿

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();

// TODO : Find out the bounding box of current triangle.
// iterate through the pixel and find if the current pixel is inside the triangle

// check triangle coordinates
// for(auto idx : {0, 1, 2})
// {
// std::clog << "pt" << idx << " | " << v[idx].x()
// << " | " << v[idx].y()
// << " | " << v[idx].z()
// << " | " << v[idx].w() << std::endl;
// }

// get bounding box
auto ext_pt_x = std::minmax_element(v.begin(), v.end(),
[](const Eigen::Vector4f& lhs, const Eigen::Vector4f & rhs){
return lhs.x() < rhs.x();
});
auto ext_pt_y = std::minmax_element(v.begin(), v.end(),
[](const Eigen::Vector4f& lhs, const Eigen::Vector4f & rhs){
return lhs.y() < rhs.y();
});
// std::clog << "ext_pt_x: " << ext_pt_x.first->x() << " | " << ext_pt_x.second->x() << std::endl;
// std::clog << "ext_pt_y: " << ext_pt_y.first->y() << " | " << ext_pt_y.second->y() << std::endl;

int min_x = floor(ext_pt_x.first->x());
int max_x = ceil(ext_pt_x.second->x());
int min_y = floor(ext_pt_y.first->y());
int max_y = ceil(ext_pt_y.second->y());

Eigen::Vector3f v3f[3];
for (int idx : {0, 1, 2})
{
v3f[idx] << v[idx].x(), v[idx].y(), 1.0f;
}
// std::transform(std::begin(v), std::end(v), v3f.begin(), [](auto& vec) { return Eigen::Vector3f(vec.x(), vec.y(), vec.z()); });

// 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;

// loop [min_x, max_x] x [min_y, max_y]
for (int x=min_x;x<=max_x;++x)
{
for (int y=min_y;y<=max_y;++y)
{
// // apply msaa
int sup_px_cnt = 0;
for (int x_sup: {0, 1})
{
for (int y_sup: {0, 1})
{
float x_pos = (float)x + 0.25 + x_sup*0.5;
float y_pos = (float)y + 0.25 + y_sup*0.5;

auto[alpha, beta, gamma] = computeBarycentric2D(x_pos, y_pos, 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;

int buff_ind = (x*2 + x_sup) + (y*2 + y_sup)*width*2;
if (insideTriangle(x_pos, y_pos, v3f))
{
if ((-z_interpolated<depth_buf_msaa2x2[buff_ind]))
{
depth_buf_msaa2x2[buff_ind] = -z_interpolated;
++sup_px_cnt;
}
}
}
}
if ((sup_px_cnt>0))
{
float intensity = (float)sup_px_cnt / 4.0f;
mix_pixel(Eigen::Vector3f(x, y, 1.0f), t.getColor()*intensity);
}
}

}
}

运行结果

screenShot.png

3. 运行结果

Assignment2hwk.png