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压缩包

相关推荐
17岁的勇气5 天前
Unity Shader unity文档学习笔记(十九):粘土效果,任意网格转化成一个球(顶点动画,曲面着色器)
笔记·学习·unity·图形渲染·顶点着色器·曲面着色器
郝学胜-神的一滴8 天前
Horse3D引擎研发笔记(四):在QtOpenGL下仿three.js,封装EBO绘制四边形
c++·3d·unity·游戏引擎·godot·图形渲染·虚幻
郝学胜-神的一滴9 天前
Horse3D引擎研发笔记(一):从使用Qt的OpenGL库绘制三角形开始
c++·qt·3d·unity·图形渲染·unreal engine
爱思德学术10 天前
中国计算机学会(CCF)推荐学术会议-A(计算机图形学与多媒体):VR 2026
计算机视觉·图形渲染·虚拟现实·用户界面
郝学胜-神的一滴14 天前
OpenGL状态机与对象管理:优化图形渲染的高效方法
开发语言·c++·程序人生·算法·图形渲染
张人大 Renda Zhang14 天前
如何用分布式架构视角理解宇宙稳定性?从精细调参到微服务的类比思考
前端·分布式·微服务·架构·图形渲染
郝学胜-神的一滴16 天前
能表示旋转的矩阵是一个流形吗?
线性代数·矩阵·图形渲染
赤水无泪18 天前
A 常见图形API和图形渲染引擎介绍
图形渲染
山楂树の19 天前
模型优化——在MacOS 上使用 Python 脚本批量大幅度精简 GLB 模型(通过 Blender 处理)
python·macos·3d·图形渲染·blender
D5Render21 天前
D5渲染器 2.11 上线丨AI 设计助手、AI PBR 材质生成与推荐、自定义路径、高级笔刷、完整支持平行投影
aigc·图形渲染·3d渲染·渲染器