【GAMES 101】作业2的实现和思考


本文为闫令琪老师的GAMES 101课程的作业2的个人实现与一些简单的思考,文中如有错漏欢迎指出。

作业要求

本次作业的任务是在屏幕上画出一个实心三角形,换言之,栅格化一个三角形。需要自己填写并调用函数 rasterize_triangle(const Triangle& t)

该函数的内部工作流程如下:

  1. 创建三角形的 2 维 bounding box。
  2. 遍历此 bounding box 内的所有像素(使用其整数索引)。然后,使用像素中心的屏幕空间坐标来检查中心点是否在三角形内。
  3. 如果在内部,则将其位置处的插值深度值 (interpolated depth value) 与深度缓冲区 (depth buffer) 中的相应值进行比较。
  4. 如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区 (depth buffer)。

代码实现

insideTriangle

测试某个点是否在三角形内部,使用叉积进行判断

static bool insideTriangle(int x, int y, const Eigen::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]
    auto v0p = Eigen::Vector2f(x-_v[0].x(), y-_v[0].y());
    auto v1p = Eigen::Vector2f(x - _v[1].x(), y - _v[1].y());
    auto v2p = Eigen::Vector2f(x - _v[2].x(), y - _v[2].y());
    auto v0v1 = Eigen::Vector2f(_v[1].x() - _v[0].x(), _v[1].y() - _v[0].y());
    auto v1v2 = Eigen::Vector2f(_v[2].x() - _v[1].x(), _v[2].y() - _v[1].y());
    auto v2v0 = Eigen::Vector2f(_v[0].x() - _v[2].x(), _v[0].y() - _v[2].y());
    
    auto z0 = v0p.x() * v0v1.y() - v0v1.x() * v0p.y();
    auto z1 = v1p.x() * v1v2.y() - v1v2.x() * v1p.y();
    auto z2 = v2p.x() * v2v0.y() - v2v0.x() * v2p.y();

    bool all_negative = z0 < 0 && z1 < 0 && z2 < 0;
    bool all_positive = z0 > 0 && z1 > 0 && z2 > 0;
    return all_negative || all_positive;   
}

rasterize_triangle

按照流程的指引编写即可

void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();
    
    // TODO : Find out the bounding box of current triangle.
    float xmin = min(v[0].x(), min(v[1].x(), v[2].x()));
    float xmax = max(v[0].x(), max(v[1].x(), v[2].x()));
    float ymin = min(v[0].y(), min(v[1].y(), v[2].y()));
    float ymax = max(v[0].y(), max(v[1].y(), v[2].y()));

    xmin = (int)floor(xmin);
    xmax = (int)ceil(xmax);
    ymin = (int)floor(ymin);
    ymax = (int)ceil(ymax);

    // 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 x = xmin; x <= xmax; x++)
    {
        for (int y = ymin; y <= ymax; y++)
        {
            if (insideTriangle(x + 0.5, y + 0.5, t.v))
            {
                auto[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;
                // printf("%f %f\n", v[0].z(), t.getColor().x());
                
                // 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)])
                {
                    depth_buf[get_index(x, y)] = z_interpolated;
                    auto color = t.getColor();
                    auto point = Eigen::Vector3f(x, y, 0);
                    set_pixel(point, color);
                }
            }
        }
    }
}

绘制结果

在这里插入图片描述

简单的思考

绘制时发现z值为-5的蓝色三角形被绘制在了z值为-2的绿色三角形前面,因为在这里计算z值时,把z值转成正的后,按照原来的计算方法,-5转成的正值比-2更小,这里只要改一改计算方法,使蓝色三角形的z值比绿色三角形更大就可以了。

//Viewport transformation
for (auto & vert : v)
{
    vert.x() = 0.5*width*(vert.x()+1.0);
    vert.y() = 0.5*height*(vert.y()+1.0);
    vert.z() = -vert.z() * f1 + f2;     // 修改后的计算方法
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值