GAMES101-LAB1

文章目录

  • 一、问题总览
  • 二、作业参考
    • [2.1 get_projection_matrix()函数](#2.1 get_projection_matrix()函数)
    • [2.2 static bool insideTriangle()函数](#2.2 static bool insideTriangle()函数)
    • [2.3 rasterize_triangle()](#2.3 rasterize_triangle())
  • 三、附件

一、问题总览

  • 在屏幕上画出一个实心三角形,换言之,栅格化一个三角形
  • 实现并调用函数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()函数,该函数在第一次作业中已被实现
cpp 复制代码
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中

  • 测试点是否在三角形内

    • 三角形边向量, 三角形顶点与测试点向量 进行叉乘;若符号相同则测试点在三角形内部,否则在外部
      • 注意,边向量要求是逆时针或者是顺时针
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,然后求和,就是该点的插值深度
cpp 复制代码
    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;
  • 完整代码
cpp 复制代码
//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压缩包

相关推荐
Padid1 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
refineiks7 天前
three.js绘制宽度大于1的线,并动态新增顶点
3d·图形渲染·webgl
Winston Wood10 天前
一个简单的例子,说明Matrix类的妙用
android·前端·图像处理·图形渲染
森龙安10 天前
VulkanTutorial(8·Shader modules)
图形渲染
云渲染图科普匠13 天前
3d室内设计效果图渲染平台哪个好?瑞云快图怎么样?
3d·图形渲染·3dsmax
先知demons13 天前
antvG6如何实现节点动画、连线动画、切换节点图标
前端·javascript·vue.js·图形渲染·canva可画
3DCAT实时渲染云14 天前
边缘计算技术的优势与挑战
实时互动·边缘计算·图形渲染
大耳猫17 天前
Android OpenGL天空盒
android·kotlin·android studio·图形渲染
大耳猫19 天前
Android OpenGL触控反馈
android·kotlin·android studio·图形渲染
木市门19 天前
【GAMES101笔记速查——Lecture 16 Ray Tracing4】
图像处理·笔记·图形渲染