【GAMES101】作业2 Triangles and Z-buffering

本文介绍了如何使用叉乘方法实现三角形内点判断函数insideTriangle,以及如何通过包围盒和Z缓冲技术进行三角形栅格化,以优化性能并处理左手系带来的坐标问题。

作业2的内容包含两个部分:

1、完成三角形栅格化算法

2、编写函数insideTriangel,用于在栅格化的时候判断某一点是否在三角形内

insideTriangel 

如何判断某一点与三角形的内外关系,使用到的方法是叉乘,将三角形的三个顶点顺序相连形成三个有序的向量AB,BC,CA,分别与向量AP,BP,CP相乘,如果符号相同,则P在三角形内,否者在三角形外。

 实现代码如下

static bool insideTriangle(int x, int 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]
    Eigen::Vector3f p(x, y, 1);
    Eigen::Vector3f ab = _v[1] - _v[0];
    Eigen::Vector3f bc = _v[2] - _v[1];
    Eigen::Vector3f ca = _v[0] - _v[2];

    Eigen::Vector3f ap = p - _v[0];
    Eigen::Vector3f bp = p - _v[1];
    Eigen::Vector3f cp = p - _v[2];

    if (ab.cross(ap).dot(bc.cross(bp)) > 0 &&
        ab.cross(ap).dot(ca.cross(cp)) > 0) {
        return true;
    }
    else {
        return false;
    }
}

 三角形栅格化

代码框架的注释中其实给出了具体的思路

1、获取三角形的包围盒,用于减少计算量,不至于遍历屏幕上的每一个点

    // TODO : Find out the bounding box of current triangle.
    float Xmin = INT_MAX;
    float Xmax = INT_MIN;
    float Ymin = INT_MAX;
    float Ymax = INT_MIN;
    for (auto v : t.v) {
        Xmin = std::min(Xmin, v.x());
        Xmax = std::max(Xmax, v.x());
        Ymin = std::min(Ymin, v.y());
        Ymax = std::max(Ymax, v.y());
    }

2、遍历包围盒中的每一个像素,并且判断是否在三角形内部

这一步用到了insideTriangle函数,注意的是并不是针对x,y坐标计算是否在三角形内,而是计算每个像素中心是否在三角形内部,所以是x+0.5,y+0.5

    for (int x = Xmin; x <= Xmax; x++) {
        for (int y = Ymin; y <= Ymax; y++) {
            if (insideTriangle(x + 0.5, y + 0.5, t.v)) {
                float alpha, beta, gamma;
                std::tie(alpha, beta, gamma) = computeBarycentric2D(x+0.5, y+0.5, 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;
                if (z_interpolated < depth_buf[get_index(x, y)]) {
                    depth_buf[get_index(x, y)] = z_interpolated;
                    set_pixel(Vector3f(x, y, 1), t.getColor());
                }
            }
        }
    }

第二个if语句实现了z-buffer深度缓存,判断当前点的z值是否小于buffer中存储的值,只有当该z值小于buffer中的值时,才会将该点显示在屏幕上,并且更新z-buffer

运行结果

        三角形上下颠倒的原因可能是框架中使用的时左手系,所以与作业1的结果不太一样。 

Games101 课程作业 2 中,模型无法正确渲染通常与以下几个方面有关:模型数据加载、视图变换、投影变换、光栅化逻辑以及绘制函数实现等。以下是可能的问题排查与解决方案: ### 检查模型数据加载 模型渲染问题可能源自模型数据未正确加载。确保模型文件(如 `.obj` 文件)路径正确,并且文件内容被正确解析。检查是否读取了顶点坐标、面索引等信息,同时确保顶点数据以正确格式存储到内存中。 ### 检查视图变换和投影变换 在 Games101 作业 2 中,需要实现模型的视图变换和投影变换。确认以下几点: - **相机位置**:确保相机位置和目标点设置正确,避免模型位于视锥体之外。 - **投影矩阵**:确认投影矩阵是否正确构建,包括透视投影或正交投影的参数(如视野角、宽高比、近裁剪平面和远裁剪平面)。 - **变换顺序**:模型变换(平移、旋转、缩放)应先于视图变换和投影变换。确保矩阵相乘的顺序正确,通常为 `MVP = Projection * View * Model`。 ### 光栅化逻辑问题 光栅化阶段的错误可能导致模型无法正确绘制。检查以下内容: - **三角形光栅化**:确保 `rasterize_triangle` 函数正确实现,包括判断像素是否在三角形内部、插值计算颜色等。 - **Z 缓冲区**:如果启用了深度测试,确保 Z 缓冲区正确初始化,并在光栅化过程中更新和比较深度值。 - **透视除法**:在投影变换后,顶点坐标需经过透视除法(除以 w),确保这一步骤正确执行。 ### 绘制函数实现 检查绘制函数是否正确调用并传递了模型数据。确保以下内容: - **顶点缓冲区**:模型顶点数据是否正确绑定到缓冲区,并在绘制函数中正确使用。 - **绘制模式**:确认绘制模式(如 `GL_TRIANGLES`)与模型数据的组织方式一致。 - **着色器程序**:如果使用了着色器,确保顶点着色器和片段着色器正确编译,并且属性和 Uniform 变量绑定正确。 ### 调试工具与方法 为了更高效地定位问题,可以使用以下调试方法: - **日志输出**:在关键步骤输出调试信息,例如模型顶点数量、变换矩阵的值、光栅化过程中的像素坐标等。 - **可视化辅助**:尝试在屏幕上绘制简单的辅助线或点,例如绘制模型包围盒,确保模型确实位于可视区域内。 - **简化模型**:使用简单的模型(如立方体或三角形)进行测试,排除复杂模型本身的问题。 ### 示例代码片段 以下是一个简化的绘制函数示例,展示如何正确绑定顶点数据并进行绘制: ```cpp void draw_model(const Model& model, const Matrix4f& mvp) { // 绑定顶点缓冲区 glBindBuffer(GL_ARRAY_BUFFER, model.vbo); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); glEnableVertexAttribArray(0); // 设置 MVP 矩阵 glUniformMatrix4fv(glGetUniformLocation(shader_program, "MVP"), 1, GL_FALSE, mvp.data()); // 绘制模型 glDrawArrays(GL_TRIANGLES, 0, model.vertices.size()); } ``` ### 相关问题 1. Games101 作业 2 中如何正确实现投影矩阵? 2. 如何在 Games101 作业 2 中调试光栅化逻辑? 3. Games101 作业 2 中如何正确加载和解析 .obj 模型文件? 4. Games101 作业 2 中如何实现 Z 缓冲区以避免模型渲染错误? 5. Games101 作业 2 中如何使用着色器进行模型渲染?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值