GAMES101作业2

声明:使用的是vs2022版,以下内容如有问题,感谢各位大佬指正!

作业要求:

作业目的:在屏幕上画出一个实心的三角形(深度测试)

我们需要做的:
| 💡在main.cpp中修改
|
| 1. Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();//中粘贴自己第一次的代码
| 2. rasterize_triangle(): 执行三角形栅格化算法//写包围盒、判断采样点、透视矫正插值计算、深度测试、像素更新
| 3. static bool insideTriangle(): 测试点是否在三角形内。你可以修改此函数的定义,这意味着,你可以按照自己的方式更新返回类型或函数参数。

关键词:包围盒;插值计算;深度测试;判断点是否在三角形内;光栅化;

1.粘贴自己第一次代码

cpp 复制代码
Eigen::Matrix4f get_projection_matrix(float eye_fov, float aspect_ratio,float zNear, float zFar)
{
    // Students will implement this function

    Eigen::Matrix4f projection = Eigen::Matrix4f::Identity();

    // TODO: Implement this function
    // Create the projection matrix for the given parameters.
    // Then return it.
    
    //粘贴第一次作业
    float n = zNear;
    float f = zFar;
    Eigen::Matrix4f M_persp2Ortho;
    M_persp2Ortho << n, 0, 0, 0,
        0, n, 0, 0,
        0, 0, n + f, -n * f,
        0, 0, 1, 0;

    float fov = eye_fov * MY_PI / 180.0;
    float t = -n * tan(fov / 2.);//解决原三角倒着的方法,将t换为-t
    float b = -t;
    float r = aspect_ratio * t;
    float l = -r;
    
    Eigen::Matrix4f M_ortho, trans, scale;
    trans << 1, 0, 0, -(r + l) / 2,
        0, 1, 0, -(t + b) / 2,
        0, 0, 1, -(n + f) / 2,
        0, 0, 0, 1;
    scale << 2 / (r - l), 0, 0, 0,
        0, 2 / (t - b), 0, 0,
        0, 0, 2 / (n - f), 0,
        0, 0, 0, 1;
    M_ortho = scale * trans;

    projection = M_ortho * M_persp2Ortho;
    return projection;
}

2.rasterize_triangle(): 执行三角形栅格化算法

分三步:

1.写三角形包围盒,计算三角形在屏幕空间的边界值

cpp 复制代码
void rst::rasterizer::rasterize_triangle(const Triangle& t)
{
    auto v = t.toVector4();//v 是三角形三个顶点的齐次坐标(x,y,z,w)
    
    // TODO : Find out the bounding box of current triangle.
    
    //包围盒(计算三角形在屏幕空间中的边界值)AABB
    float min_x = width;
    float max_x = 0;
    float min_y = height;
    float max_y = 0;

    for (int i = 0; i < 3; i++)
    {
        min_x = std::min(v[i].x(), min_x);
        max_x = std::max(v[i].x(), max_x);
        min_y = std::min(v[i].y(), min_y);
        max_y = std::max(v[i].y(), max_y);
    }

2.判断采样点是否在三角形内,计算采样点的重心坐标,然后透视矫正插值计算深度和颜色

https://zhuanlan.zhihu.com/p/403259571#:~:text=这里我们采用线性插值,可以得到P'%3DA'%2Bm (B'-A'),如果设|A'B'|为1,则|A'P'|为m,|P'B'|为1-m。 现在我们的问题是:已知屏幕上一点P',且 P'%3D (1-m)A'%2BmB' ,还有顶点A和B的世界坐标,,需要求出与P'对应的点P关于AB的表示: P%3D (1-n)A%2BnB 。 公式推导 这里我添加两条辅助线,方便公式推导:从A和B作竖直线,分别交P'P延长线上的G和K。//来自知乎文章---图形学 - 关于透视矫正插值那些事

cpp 复制代码
    // iterate through the pixel and find if the current pixel is inside the triangle
    //遍历像素,找出当前像素是否在三角形内
    // If so, use the following code to get the interpolated z value.
    //如果是这样,请使用以下代码获取插值z值。
    //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;
    
    for (int y = min_y; y < max_y; y++)
    {
        for (int x = min_x; x < max_x; x++)
        {
            //遍历边界框内的所有像素,检查中心点是否在三角形内
            if (insideTriangle(x + 0.5, y + 0.5, t.v))//使用 (x + 0.5, y + 0.5) 作为像素中心点
            {
                //透视矫正插值计算深度和颜色
                auto [alpha, beta, gamma] = computeBarycentric2D(x + 0.5, y + 0.5, t.v);//计算该点的重心坐标
                // 计算:1/(α + β + γ)
                float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
                // 计算:α(z₀/w₀) + β(z₁/w₁) + γ(z₂/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;

                

3.深度测试与像素更新

cpp 复制代码
// TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.

                int index = get_index(x, y);
                if (z_interpolated < depth_buf[index]) 
                {
                    Eigen::Vector3f p;
                    p << x, y, z_interpolated;
                    set_pixel(p, t.getColor());
                    depth_buf[index] = z_interpolated;
                }
            }
        }
    }
}

2.rasterize_triangle():的完整代码

cpp 复制代码
void rst::rasterizer::rasterize_triangle(const Triangle& t)
{
    auto v = t.toVector4();//v 是三角形三个顶点的齐次坐标(x,y,z,w)
    
    // TODO : Find out the bounding box of current triangle.
    
    //包围盒(计算三角形在屏幕空间中的边界值)AABB
    float min_x = width;
    float max_x = 0;
    float min_y = height;
    float max_y = 0;

    for (int i = 0; i < 3; i++)
    {
        min_x = std::min(v[i].x(), min_x);
        max_x = std::max(v[i].x(), max_x);
        min_y = std::min(v[i].y(), min_y);
        max_y = std::max(v[i].y(), max_y);
    }

    // iterate through the pixel and find if the current pixel is inside the triangle
    // 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;
    
    for (int y = min_y; y < max_y; y++)
    {
        for (int x = min_x; x < max_x; x++)
        {
            //遍历边界框内的所有像素,检查中心点是否在三角形内
            if (insideTriangle(x + 0.5, y + 0.5, t.v))//使用 (x + 0.5, y + 0.5) 作为像素中心点
            {
                //透视矫正插值计算深度和颜色
                auto [alpha, beta, gamma] = computeBarycentric2D(x + 0.5, y + 0.5, t.v);//计算该点的重心坐标
                // 计算:1/(α + β + γ)
                float w_reciprocal = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
                // 计算:α(z₀/w₀) + β(z₁/w₁) + γ(z₂/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.
                // 深度测试与像素更新
                int index = get_index(x, y);//将坐标转化为索引
                if (z_interpolated < depth_buf[index]) //将当前像素的深度值和缓冲区中的进行比较
                {
                    //z 值越小越近
                    //如果当前像素更近,就更新颜色和深度缓冲区
                    Eigen::Vector3f p;
                    p << x, y, z_interpolated;
                    //更新帧缓冲区的颜色
                    set_pixel(p, t.getColor());
                    //更新深度缓冲区的值
                    depth_buf[index] = z_interpolated;
                }
            }
        }
    }
}

3.测试点是否在三角形内(叉积)Cross product

cpp 复制代码
static bool insideTriangle(float x, float y, const Vector3f* _v)
{   
    // TODO : Implement this function to check if the point (x, y) is inside the triangle represented by _v[0], _v[1], _v[2]

    int flag = -1;

    for (int i = 0; i < 3; i++)
    {
        Eigen::Vector3f p0 = { x,y,0 };       //待检测点
        Eigen::Vector3f p1 = _v[i];           //当前边的起点
        Eigen::Vector3f p2 = _v[(i + 1) % 3]; //当前边的终点

        Eigen::Vector3f v1 = p1 - p0;         //从待检测点到边起点的向量
        Eigen::Vector3f v2 = p1 - p2;         //边的方向向量

        float cp = v1.cross(v2).z();          //计算叉积的z分量
        if (cp == 0) continue;                // 点在边上,继续检查下一条边

        int sign = cp < 0 ? 0 : 1;            // 获取叉积的符号(0为负,1为正)
        if (flag == -1) flag = sign;          // 记录第一个非零叉积的符号
        if (flag != sign)return false;        // 符号不一致,点在三角形外部
    }

    return true;                              // 所有边的叉积符号一致,点在三角形内部
    
 }

最后运行,得到这幅图


相关推荐
丶Darling.18 天前
26考研 | 王道 | 第六章 应用层
计算机网络·考研·学习笔记·王道
丶Darling.23 天前
26考研 | 王道 | 第五章 传输层
计算机网络·考研·学习笔记·王道
Be_Somebody23 天前
计算机图形学——Games101深度解析_第二章
游戏开发·计算机图形学·games101
Be_Somebody24 天前
计算机图形学——Games101深度解析_第一章
游戏开发·计算机图形学·games101
Alice-YUE1 个月前
【CSS学习笔记1】css基础知识介绍
css·学习笔记
再睡一夏就好1 个月前
从硬件角度理解“Linux下一切皆文件“,详解用户级缓冲区
linux·服务器·c语言·开发语言·学习笔记
Asymptote02131 个月前
【内网渗透】——S4u2扩展协议提权以及KDC欺骗提权
网络协议·信息安全·学习笔记·渗透·内网渗透·奇安信·kaliklinux
再睡一夏就好1 个月前
C语言常见的文件操作函数总结
c语言·开发语言·c++·笔记·学习笔记
丶Darling.2 个月前
26考研 | 王道 | 计算机网络 | 第一章 计算机网络的体系结构
计算机网络·考研·学习笔记