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;                              // 所有边的叉积符号一致,点在三角形内部
    
 }

最后运行,得到这幅图


相关推荐
四谎真好看7 天前
SSM学习笔记(SpringBoot篇)
spring boot·笔记·学习·学习笔记·ssm
~黄夫人~8 天前
Linux 权限管理:用户组 + 特殊权限 + ACL 解析
linux·运维·计算机·学习笔记·权限管理
四谎真好看10 天前
SSM学习笔记(SpringMVC篇 Day02)
笔记·学习·学习笔记·ssm
四谎真好看12 天前
SSM学习笔记(SpringMVC篇 Day01)
笔记·学习·学习笔记·ssm
heartbeat..16 天前
Java 微服务初学者入门指南(CSDN 博客版)
java·运维·微服务·学习笔记·入门
四谎真好看16 天前
SSM学习笔记(Spring篇Day03)
笔记·学习·学习笔记·ssm
四谎真好看17 天前
SSM学习笔记(Spring篇 Day02)
笔记·学习·学习笔记·ssm
四谎真好看19 天前
SSM学习笔记(Spring篇 Day01)
笔记·学习·学习笔记·ssm
四谎真好看20 天前
JavaWeb学习笔记(Day14)
笔记·学习·学习笔记·javaweb
四谎真好看24 天前
JavaWeb学习笔记(Day13)
笔记·学习·学习笔记·javaweb