GAMES101-LAB1

发布时间:2023年12月25日


一、问题总览

  • 在屏幕上画出一个实心三角形,换言之,栅格化一个三角形
  • 实现并调用函数rasterize_triangle(const Triangle& t)
    1. 创建三角形的2维bounding box。
    2. 遍历此bounding box内的所有像素(使用其整数索引)。然后,使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。
    3. 如果在内部,则将其位置处的插值深度值(interpolated depth value) 与深度缓冲区(depth buffer) 中的相应值进行比较。
    4. 如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区(depth buffer)。
  • 需要修改的函数
    • rasterize_triangle(): 执行三角形栅格化算法
    • static bool insideTriangle(): 测试点是否在三角形内。你可以修改此函数的定义,这意味着,你可以按照自己的方式更新返回类型或函数参数。
  • 对于三角形内部的像素,需要根据三角形顶点值进行插值,得到其深度值。插值的深度值被储存在变量z_interpolated中。
  • 为了方便写代码,已将z进行了反转,保证都是正数,并且越大表示离视点越远。
  • 在此次作业中,无需处理旋转变换,只需为模型变换返回一个单位矩阵。最后,提供了两个hard-coded三角形来测试实现,如果程序实现正确,将看到如下所示的输出图像:
    在这里插入图片描述

二、作业参考

2.1 get_projection_matrix()函数

  • 填充main.cpp下的get_projection_matrix()函数,该函数在第一次作业中已被实现
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,
                                      float zNear, float zFar)
{
    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

    Eigen::Matrix4f persp_matrix;//透视矩阵 
    Eigen::Matrix4f translate_matrix;//移动矩阵
    Eigen::Matrix4f scale_matirx;//缩放矩阵

    persp_matrix << zNear, 0, 0, 0,
                    0, zNear, 0, 0,
                    0, 0, zNear + zFar, -zNear * zFar,
                    0, 0, 1, 0;
    
    float halfAngle = eye_fov / 2 / 180 * MY_PI;
    float height = -2 * std::tan(halfAngle) * zNear;//没有负号则三角形上下颠倒
    float width = height * aspect_ratio;

    translate_matrix << 1, 0, 0, 0,
                        0, 1, 0, 0, 
                        0, 0, 1, -(zNear + zFar) / 2,
                        0, 0, 0, 1;
    scale_matirx << 2 / width, 0, 0, 0,
                    0, 2 / height, 0, 0,
                    0, 0, 2 / (zNear - zFar), 0,
                    0, 0, 0, 1;

    projection = scale_matirx * translate_matrix * persp_matrix;

    return projection;
}

2.2 static bool insideTriangle()函数

  • 函数在rasterizer.cpp中

  • 测试点是否在三角形内
    在这里插入图片描述

    • 三角形边向量, 三角形顶点与测试点向量 进行叉乘;若符号相同则测试点在三角形内部,否则在外部
      • 注意,边向量要求是逆时针或者是顺时针
static bool insideTriangle(int x, int y, const Vector3f* _v)
{   
    bool sign[3];//记录三角形边向量和测试点顶点向量叉乘符号
    for(int i = 0; i < 3; i++){
        Vector3f vec1(x - _v[i].x(), y - _v[i].y(), 1);//测试点顶点向量
        Vector3f vec2(_v[(i + 1) % 3].x() - _v[i].x(), _v[(i + 1) % 3].y() - _v[i].y(), 1);//边向量
        sign[i] = vec1.cross(vec2).z() > 0;
    }
    if(sign[0] == sign[1] && sign[0] == sign[2]) return true;//符号相同,则在三角形内
    return false;
}

2.3 rasterize_triangle()

  • 函数在rasterizer.cpp中
  • 执行三角形栅格化算法
  • 使用重心坐标插值方法获得采样点深度
    • alpha, beta, gamma求法如下
    • 三个顶点的深度分别乘以alpha, beta, gamma,然后求和,就是该点的插值深度
      在这里插入图片描述
    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;
  • 完整代码
//Screen space rasterization
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();
    
    // TODO : Find out the bounding box of current triangle.
    int bounding_box_x_left = std::min(v[0].x(), std::min(v[1].x(), v[2].x()));
    int bounding_box_x_right = std::max(v[0].x(), std::max(v[1].x(), v[2].x()));
    int bounding_box_y_left = std::min(v[0].y(), std::min(v[1].y(), v[2].y()));
    int bounding_box_y_right = std::max(v[0].y(), std::max(v[1].y(), v[2].y()));

    // iterate through the pixel and find if the current pixel is inside the triangle
    for(int x = bounding_box_x_left; x <= bounding_box_x_right; x++){
        for(int y = bounding_box_y_left; y <= bounding_box_y_right; y++){
            if(insideTriangle(x, y, 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.
                if(z_interpolated < depth_buf[get_index(x, y)]){//z保证都是正数,并且越大表示离视点越远
                // 如果(x,y)离视点近,则需要重新绘制
                    depth_buf[get_index(x, y)] = z_interpolated;
                    set_pixel(Eigen::Vector3f(x, y, z_interpolated), t.getColor());
                }
            }
        }
    }
}

三、附件

作业2压缩包

文章来源:https://blog.csdn.net/qq_39876147/article/details/135197420
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。