# 作业要求

完善以下函数:

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

# 三角形栅格化

  1. 计算三角形的包围盒

    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())));
  2. 遍历包围盒内的每个像素,判断像素是否在三角形内,顺便加上 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)]);
            }
        }
    }

插值深度时,需要先计算出插值的重心坐标,然后再计算插值的深度。

α=x(v1.yv2.y)+(v2.xv1.x)y+v1.xv2.yv2.xv1.yv0.x(v1.yv2.y)+(v2.xv1.x)v0.y+v1.xv2.yv2.xv1.yβ=x(v2.yv0.y)+(v0.xv2.x)y+v2.xv0.yv0.xv2.yv1.x(v2.yv0.y)+(v0.xv2.x)v1.y+v2.xv0.yv0.xv2.yγ=x(v0.yv1.y)+(v1.xv0.x)y+v0.xv1.yv1.xv0.yv2.x(v0.yv1.y)+(v1.xv0.x)v2.y+v0.xv1.yv1.xv0.ywreciprocal=(αv0.w+βv1.w+γv2.w)1zinterpolated=(αv0.zv0.w+βv1.zv1.w+γv2.zv2.w)wreciprocal\alpha = \frac{x \cdot (v_1.y - v_2.y) + (v_2.x - v_1.x) \cdot y + v_1.x \cdot v_2.y - v_2.x \cdot v_1.y}{v_0.x \cdot (v_1.y - v_2.y) + (v_2.x - v_1.x) \cdot v_0.y + v_1.x \cdot v_2.y - v_2.x \cdot v_1.y} \\ \beta = \frac{x \cdot (v_2.y - v_0.y) + (v_0.x - v_2.x) \cdot y + v_2.x \cdot v_0.y - v_0.x \cdot v_2.y}{v_1.x \cdot (v_2.y - v_0.y) + (v_0.x - v_2.x) \cdot v_1.y + v_2.x \cdot v_0.y - v_0.x \cdot v_2.y} \\ \gamma = \frac{x \cdot (v_0.y - v_1.y) + (v_1.x - v_0.x) \cdot y + v_0.x \cdot v_1.y - v_1.x \cdot v_0.y}{v_2.x \cdot (v_0.y - v_1.y) + (v_1.x - v_0.x) \cdot v_2.y + v_0.x \cdot v_1.y - v_1.x \cdot v_0.y} \\ w_{\text{reciprocal}} = \left(\frac{\alpha}{v_0.w} + \frac{\beta}{v_1.w} + \frac{\gamma}{v_2.w}\right)^{-1} \\ z_{\text{interpolated}} = \left( \alpha \frac{v_0.z}{v_0.w} + \beta \frac{v_1.z}{v_1.w} + \gamma \frac{v_2.z}{v_2.w} \right) \cdot w_{\text{reciprocal}}

# 去黑边

  1. rasterizer.hpp 中添加两个成员变量,分别用于存储每个采样像素的颜色和深度。

    //rasterizer.hpp
        private:
            std::vector<Eigen::Vector3f> frame_sample_buf;
            std::vector<float> depth_sample_buf;
  2. 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());
        }
    }