# 作业要求
完善以下函数:
rasterize_triangle(): 执行三角形栅格化算法 | |
static bool insideTriangle(): 测试点是否在三角形内。你可以修改此函数的定义,这意味着,你可以按照自己的方式更新返回类型或函数参数。 |
# 作业实现
# 测试点是否在三角形内
把给出的点与三角形的三个顶点分别做叉乘,如果这三个叉乘的结果符号相同,那么这个点在三角形内。
static bool insideTriangle(const float x, const float y, const Vector3f *_v) { | |
const Eigen::Vector3f p(x, y, 1); | |
for (int i = 0; i < 3; i++) { | |
Eigen::Vector3f v0 = _v[i]; | |
Eigen::Vector3f v1 = _v[(i + 1) % 3]; | |
Eigen::Vector3f edge = v1 - v0; | |
if (Eigen::Vector3f vp = p - v0; edge.cross(vp).z() < 0) { | |
return false; | |
} | |
} | |
return true; | |
} |
# 三角形栅格化
-
计算三角形的包围盒
const int x_min = static_cast<int>(std::min(v[0].x(), std::min(v[1].x(), v[2].x())));
const int x_max = static_cast<int>(std::max(v[0].x(), std::max(v[1].x(), v[2].x())));
const int y_min = static_cast<int>(std::min(v[0].y(), std::min(v[1].y(), v[2].y())));
const int y_max = static_cast<int>(std::max(v[0].y(), std::max(v[1].y(), v[2].y())));
-
遍历包围盒内的每个像素,判断像素是否在三角形内,顺便加上 MSAA
for (auto x = x_min; x <= x_max; x++) {
for (auto y = y_min; y <= y_max; y++) {
auto sample_count = 0;
auto z_min = std::numeric_limits<float>::infinity();
auto vid = get_index(x, y) * 4;
for (int i = 0; i < 4; i++) {
if (insideTriangle(static_cast<float>(x) + axis_x[i], static_cast<float>(y) + axis_y[i], t.v)) {
auto [alpha, beta, gamma] = computeBarycentric2D(static_cast<float>(x) + axis_x[i], static_cast<float>(y) + axis_y[i], 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;
sample_count++;
if (-z_interpolated < depth_sample_buf[vid + i]) {
depth_sample_buf[vid + i] = -z_interpolated;
frame_sample_buf[vid + i] = t.getColor() / 4;
z_min = std::min(z_min, -z_interpolated);
}
}
}
if (sample_count > 0) {
depth_buf[get_index(x, y)] = z_min;
frame_buf[get_index(x, y)] = Eigen::Vector3f{0, 0, 0};
for (int i = 0; i < 4; i++) {
frame_buf[get_index(x, y)] += frame_sample_buf[vid + i];
}
set_pixel(Eigen::Vector3f(x, y, 0), frame_buf[get_index(x, y)]);
}
}
}
插值深度时,需要先计算出插值的重心坐标,然后再计算插值的深度。
# 去黑边
-
在
rasterizer.hpp
中添加两个成员变量,分别用于存储每个采样像素的颜色和深度。//rasterizer.hpp
private:
std::vector<Eigen::Vector3f> frame_sample_buf;
std::vector<float> depth_sample_buf;
-
在
rasterizer.cpp
中增加对应的初始化和清空函数。//rasterizer.cpp
rst::rasterizer::rasterizer(int w, int h) : width(w), height(h) {
frame_buf.resize(w * h);
depth_buf.resize(w * h);
frame_sample_buf.resize(w * h * 4);
depth_sample_buf.resize(w * h * 4);
}
void rst::rasterizer::clear(rst::Buffers buff) {
if ((buff & rst::Buffers::Color) == rst::Buffers::Color) {
std::fill(frame_buf.begin(), frame_buf.end(), Eigen::Vector3f{0, 0, 0});
std::fill(frame_sample_buf.begin(), frame_sample_buf.end(), Eigen::Vector3f{0, 0, 0});
}
if ((buff & rst::Buffers::Depth) == rst::Buffers::Depth) {
std::fill(depth_buf.begin(), depth_buf.end(), std::numeric_limits<float>::infinity());
std::fill(depth_sample_buf.begin(), depth_sample_buf.end(), std::numeric_limits<float>::infinity());
}
}