Games101作业2

Games101 作业2

这次作业要写两个函数,第一个是判断点是否在三角形中,第二个是光栅化一个三角形。

insideTriangle函数

static bool insideTriangle(int x, int y, const Vector3f* _v)
{   
    Vector3f dir[3]; // AP,BP,CP
    Vector3f pos = Vector3f(x, y, 1);
    for (int i = 0; i < 3; ++i) {
        dir[i] = pos - _v[i];
    }

    Vector3f side[3]; // AB,BC,CA;
    for (int i = 0; i < 3; i++)
    {
        side[i] = _v[(i + 1) % 3] - _v[i];
    }
    Vector3f cross_res[3];
    for (int i = 0; i < 3; i++)
        cross_res[i] = side[i].cross(dir[i]);
    if (cross_res[0][2] > 0 && cross_res[1][2] > 0 && cross_res[2][2] > 0) return true;
    if (cross_res[0][2] < 0 && cross_res[1][2] < 0 && cross_res[2][2] < 0) return true;
    return false;
}

rasterize_triangle函数

void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();

    // bounding box
    float min_x = std::min(v[0][0], std::min(v[1][0], v[2][0]));
    float max_x = std::max(v[0][0], std::max(v[1][0], v[2][0]));
    float min_y = std::min(v[0][1], std::min(v[1][1], v[2][1]));
    float max_y = std::max(v[0][1], std::max(v[1][1], v[2][1]));

    min_x = (int)std::floor(min_x);
    max_x = (int)std::ceil(max_x);
    min_y = (int)std::floor(min_y);
    max_y = (int)std::ceil(max_y);

    bool MSAA = true;
    //MSAA 4X
    if (MSAA) {
        // 格子里的细分四个小点坐标
        std::vector pos
        {
            {0.25,0.25},
            {0.75,0.25},
            {0.25,0.75},
            {0.75,0.75},
        };
        for (int x = min_x; x <= max_x; x++) {
            for (int y = min_y; y <= max_y; y++) {
                // 记录最小深度
                float minDepth = FLT_MAX;
                // 四个小点中落入三角形中的点的个数
                int count = 0;
                // 对四个小点坐标进行判断 
                for (int i = 0; i < 4; i++) {
                    // 小点是否在三角形内
                    if (insideTriangle((float)x + pos[i][0], (float)y + pos[i][1], t.v)) {
                        // 如果在,对深度z进行插值
                        auto tup = computeBarycentric2D((float)x + pos[i][0], (float)y + pos[i][1], t.v);
                        float alpha;
                        float beta;
                        float gamma;
                        std::tie(alpha, beta, gamma) = tup;
                        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;
                        minDepth = std::min(minDepth, z_interpolated);
                        count++;
                    }
                }
                if (count != 0) {
                    if (depth_buf[get_index(x, y)] > minDepth) {
                        Vector3f color = t.getColor() * count / 4.0;
                        Vector3f point(3);
                        point << (float)x, (float)y, minDepth;
                        // 替换深度
                        depth_buf[get_index(x, y)] = minDepth;
                        // 修改颜色
                        set_pixel(point, color);
                    }
                }
            }
        }
    }
    else {
        for (int x = min_x; x <= max_x; x++) {
            for (int y = min_y; y <= max_y; y++) {
                if (insideTriangle((float)x + 0.5, (float)y + 0.5, t.v)) {
                    auto tup = computeBarycentric2D((float)x + 0.5, (float)y + 0.5, t.v);  //求得是屏幕上的重心,需要反求空间中的坐标
                    float alpha;
                    float beta;
                    float gamma;
                    std::tie(alpha, beta, gamma) = tup;
                    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;

                    if (depth_buf[get_index(x, y)] > z_interpolated) {
                        Vector3f color = t.getColor();
                        Vector3f point(3);
                        point << (float)x, (float)y, z_interpolated;
                        depth_buf[get_index(x, y)] = z_interpolated;
                        set_pixel(point, color);
                    }
                }
            }
        }
    }
}

​ 比较难以理解的是中间重心坐标求深度插值的几步,注意,我们computBarycentric2d函数求的是屏幕的重心坐标,因为在计算重心前,我们已经进行了 r.draw(pos_id, ind_id, col_id, rst::Primitive::Triangle);函数,而在这个函数中,三角形已经进行了mvp变化,所以我们计算重心的传参是已经经过了mvp的顶点坐标,得到了屏幕重心坐标,需要反求出三维空间中三角形的重心坐标,而这个可以参考数学推导.

你可能感兴趣的:(几何学,图论)