【Games101】作业2详解

前言

本人是菜B,这节课的作业琢磨了很久,力求将每个知识点搞懂,特写下博客记录,既是总结方法论,也希望能帮助到大家

前置知识

1.需要先完成作业1并且理解三角形光栅化课堂的内容,包括光栅化的步骤,MSAA超采样
2.建议熟悉框架再来动手,否则很难发现问题解决问题

作业目标


在这里插入图片描述

如何光栅化三角形?

在这里插入图片描述

老师的pdf已经说的很明确了,就不多说了

三角形光栅化代码

void rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();
    int minx, maxx, miny, maxy;     //定义一个三角形的覆盖面boundingBox
    minx = min(v[0].x(), min(v[1].x(), v[2].x()));
    maxx = max(v[0].x(), max(v[1].x(), v[2].x()));
    miny = min(v[0].y(), min(v[1].y(), v[2].y()));
    maxy = max(v[0].y(), max(v[1].y(), v[2].y()));

    //循环判断每个点是否在三角形内
    for (int x = minx; x <= maxx; ++x) {
        for (int y = miny; y <= maxy; ++y) {
            if (insideTriangle(x + 0.5, y + 0.5, t.v)) {
                //求深度插值
                float alpha, beta, gamma;
                tie(alpha, beta, gamma) = computeBarycentric2D(x+0.5, y+0.5, t.v);  //取tuple值用tie流式比较简单
                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;
                //光栅化
                auto ind = get_index(x, y);
                if (z_interpolated < depth_buf[ind]) {
                    depth_buf[ind] = z_interpolated;
                    Vector3f point = Vector3f((float)x,(float)y, z_interpolated);
                    Vector3f color = t.getColor();
                    set_pixel(point, color);
                }
            }
        }
    }
    // If so, use the following code to get the interpolated z value.
    // TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
}

如何判断采样点是否在三角形内?

有很多方法,这里采用叉乘同向判断,具体可以看这个博客Games101-作业问题整理
在这里插入图片描述
代码

static bool insideTriangle(float x, float y, const Vector3f* _v)
{   
    Vector3f Q = Vector3f(x, y, 1);
    
    Vector3f v0v1 = _v[1] - _v[0];
    Vector3f v0Q = Q - _v[0];
    float z0 = v0v1.cross(v0Q).z();

    Vector3f v1v2 = _v[2] - _v[1];
    Vector3f v1Q = Q - _v[1];
    float z1 = v1v2.cross(v1Q).z();

    Vector3f v2v0 = _v[0] - _v[2];
    Vector3f v2Q = Q - _v[2];
    float z2 = v2v0.cross(v2Q).z();

    if (z0 > 0) {
        return z1 > 0 && z2 > 0;
    }
    return z0<0 && z1<0 && z2<0; //向量叉积的正负在z轴显示,而且同号才表示在三角形内
}

PS:之前检查错误没发现这里有错,导致我梳理了好久才发现错误,记得叉乘一定是同号才能认为在三角形内

提高题

作业要求中使用的是SSAA,这里使用MSAA,我的笔记已经写的很清楚怎么算了,与一般采样相比,MSAA无非就是多了3个采样点,对每个采样点检测是否在三角形内,最后着色的时候注意覆盖三角形的边界着色

在这里插入图片描述

但是需要注意一个容易漏的点,对于4个采样点,每个采样点都需要维护它自己的深度值,这其实就涉及到对框架的改动

在这里插入图片描述

//rasterizer.hcpp代码
std::vector<Eigen::Vector3f> frame_buf;
std::vector<Eigen::Vector3f> super_frame_buf;

std::vector<float> depth_buf;	//其实只要跟踪这个变量的引用照葫芦画瓢就行
std::vector<float> super_depth_buf;
//rasterizer.cpp代码
//主要作用是清理缓存
void rasterizer::clear(Buffers buff)
{
    if ((buff & Buffers::Color) == Buffers::Color)
    {
        fill(frame_buf.begin(), frame_buf.end(), Vector3f{ 0, 0, 0 });
        fill(super_frame_buf.begin(), super_frame_buf.end(), Vector3f{ 0, 0, 0 });
    }
    if ((buff & Buffers::Depth) == Buffers::Depth)
    {
        fill(depth_buf.begin(), depth_buf.end(), numeric_limits<float>::infinity());
        fill(super_depth_buf.begin(), super_depth_buf.end(), numeric_limits<float>::infinity());
    }
}

//主要作用是定义4倍大小的分辨率
rasterizer::rasterizer(int w, int h) : width(w), height(h)
{
    frame_buf.resize(w * h);
    depth_buf.resize(w * h);
    super_frame_buf.resize(4 * w * h);
    super_depth_buf.resize(4 * w * h);
}

MSAA的处理已经很明显了,就是分辨率也要改变;这里其实还需要注意作业1中的MVP变换,如果在MVP变换中f改为了-f,那么会出现覆盖问题,所以f要改回来

int rst::rasterizer::get_super_index(int x, int y)  //2x2MSAA采样索引
{
    return (height * 2 - 1 - y) * width * 2 + x;
}

vector<Vector2f> super_sample_point
{
    {0.25,0.25},
    {0.75,0.25},
    {0.25,0.75},
    {0.75,0.75},
};
//Screen space rasterization
void rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();
    int minx, maxx, miny, maxy;     //定义一个三角形的覆盖面boundingBox
    minx = min(v[0].x(), min(v[1].x(), v[2].x()));
    maxx = max(v[0].x(), max(v[1].x(), v[2].x()));
    miny = min(v[0].y(), min(v[1].y(), v[2].y()));
    maxy = max(v[0].y(), max(v[1].y(), v[2].y()));

    //循环判断每个点是否在三角形内
    for (int x = minx; x <= maxx; ++x) {
        for (int y = miny; y <= maxy; ++y) {
            bool flag = false;   //是否通过深度测试
            for (int k = 0; k < 4; k++) {
                if (insideTriangle(x + super_sample_point[k][0], y + super_sample_point[k][1], t.v)) {
                    //求深度插值
                    float alpha, beta, gamma;
                    tie(alpha, beta, gamma) = computeBarycentric2D(x + 0.5, y + 0.5, t.v);  //取tuple值用tie流式比较简单
                    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;
                    //光栅化
                    auto ind = get_super_index(x * 2 + k % 2, y * 2 + k / 2);
                    if (z_interpolated < super_depth_buf[ind]) {
                        flag = true;
                        super_depth_buf[ind] = z_interpolated;      //深度缓存
                        super_frame_buf[ind] = t.getColor();        //颜色缓存,解决子像素点重叠黑边问题
                    }
                }
            }
            if (flag) {
                int a = get_super_index(x * 2, y * 2);      //MSAA分辨率下的4个超采样点
                int b = get_super_index(x * 2 + 1, y * 2);
                int c = get_super_index(x * 2, y * 2 + 1);
                int d = get_super_index(x * 2 + 1, y * 2 + 1);

                Vector3f point = Vector3f((float)x, (float)y, 0);
                Vector3f color = (super_frame_buf[a] + super_frame_buf[b] + super_frame_buf[c] + super_frame_buf[d]) / 4;
                set_pixel(point, color);
            }
        }
    }
    // If so, use the following code to get the interpolated z value.
    // TODO : set the current pixel (use the set_pixel function) to the color of the triangle (use getColor function) if it should be painted.
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值