作业2:Triangles and Z-buffering

本文详细讲解了如何计算三角形的边界框,使用叉乘法判断点是否在三角形内,以及MSAA4X技术中的深度和颜色采样。重点介绍了`insideTriangle`函数实现和`rasterize_triangle`中的多分辨率抗锯齿算法应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作业描述

在这里插入图片描述

函数修改

在这里插入图片描述
(1)寻找三角形的 bounding box:根据三角形的三个顶点坐标,找出最大 x 坐标、最小 x 坐标、最大 y 坐标、最小 y 坐标。需要注意的就是最小 x、y坐标需要比原数小;最大 x、y坐标需要比原数大。
(2)点是否在三角形内:连接该点与三角形三个点形成一系列向量,然后判断叉乘的结果的正负是否一致。
(3)MSAA 4X 深度:把一个点看成一个格子,判断里面4个小点是否落在三角形内,然后找到其中的最小 z 值,和帧缓冲中的 z 值进行比较替换。
(4)MSAA 4X 颜色:判断4个小点有几个落入三角形内,然后按比例对颜色进行采样。

insideTriangle函数

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 a1 = { _v[0].x() - _v[1].x(), _v[0].y() - _v[1].y(), 0 };
    Eigen::Vector3f a2 = { _v[1].x() - _v[2].x(), _v[1].y() - _v[2].y(), 0 };
    Eigen::Vector3f a3 = { _v[2].x() - _v[0].x(), _v[2].y() - _v[0].y(), 0 };
	// 该点与三角形三个顶点形成的向量 
    Eigen::Vector3f b1 = { x - _v[1].x(), y - _v[1].y(), 0 };
    Eigen::Vector3f b2 = { x - _v[2].x(), y - _v[2].y(), 0 };
    Eigen::Vector3f b3 = { x - _v[0].x(), y - _v[0].y(), 0 };
	// 做叉乘
    float c1 = a1.cross(b1).z();
    float c2 = a2.cross(b2).z();
    float c3 = a3.cross(b3).z();

    if ((c1 >= 0 && c2 >= 0 && c3 >= 0) || (c1 < 0 && c2 < 0 && c3 < 0))
        return true;
    else
        return false;
}

rasterize_triangle函数

void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();

    // bounding box
    float min_x = std::min(v[0][0], std::min(v[1][0], v[2][0]));
    float max_x = std::max(v[0][0], std::max(v[1][0], v[2][0]));
    float min_y = std::min(v[0][1], std::min(v[1][1], v[2][1]));
    float max_y = std::max(v[0][1], std::max(v[1][1], v[2][1]));

    min_x = (int)std::floor(min_x);
    max_x = (int)std::ceil(max_x);
    min_y = (int)std::floor(min_y);
    max_y = (int)std::ceil(max_y);

    bool MSAA = false;
    // MSAA 4X
    if (MSAA)
    {
        std::vector<Eigen::Vector2f> pos
        {
            {0.25, 0.25},
            {0.75, 0.25},
            {0.25, 0.75},
            {0.75, 0.75},
        };
        for (int x = min_x; x <= max_x; ++x)
        {
            for (int y = min_y; y <= max_y; ++y)
            {
                // 记录最小深度
                float minDepth = FLT_MAX;
                // 四个小点中落入三角形中的点的个数
                int count = 0;
                // 对四个小点进行判断
                for (int i = 0; i < 4; ++i)
                {
                    // 小点是否在三角形内
                    if (insideTriangle((float)x + pos[i][0], (float)y + pos[i][1], t.v))
                    {
                        // 如果在,读深度 z 进行插值
                        auto tuple = computeBarycentric2D((float)x + pos[i][0], (float)y + pos[i][1], t.v);
                        float alpha;
                        float beta;
                        float gamma;
                        std::tie(alpha, beta, gamma) = tuple;
                        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;
                        minDepth = std::min(minDepth, z_interpolated);
                        ++count;
                    }
                }
                if (count != 0)
                {
                    if (depth_buf[get_index(x, y)] > minDepth)
                    {
                        Eigen::Vector3f color = t.getColor() * count / 4.0;
                        Eigen::Vector3f point(3);
                        point << (float)x, (float)y, minDepth;
                        // 替换深度
                        depth_buf[get_index(x, y)] = minDepth;
                        // 修改颜色
                        set_pixel(point, color);
                    }
                }
            }
        }
    }
    else
    {
        for (int x = min_x; x <= max_x; ++x)
        {
            for (int y = min_y; y <= max_y; ++y)
            {
                if (insideTriangle((float)x + 0.5, (float)y + 0.5, t.v))
                {
                    auto tuple = computeBarycentric2D((float)x + 0.5, (float)y + 0.5, t.v);
                    float alpha;
                    float beta;
                    float gamma;
                    std::tie(alpha, beta, gamma) = tuple;
                    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 (depth_buf[get_index(x, y)] > z_interpolated)
                    {
                        Eigen::Vector3f color = t.getColor();
                        Eigen::Vector3f point(3);
                        point << (float)x, (float)y, z_interpolated;
                        depth_buf[get_index(x, y)] = z_interpolated;
                        set_pixel(point, color);
                    }
                }
            }
        }
    }
}

结果展示

在这里插入图片描述
如果发生上述情况错误,记得在 rasterizer.hpp中添加一条语句#include<map>
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值