Games101-Chapter6-光栅化2(反走样(抗锯齿)&深度缓存)

接上一章,采样后,出现了锯齿

------>【一些采样的理论】

光栅化的过程,就是在屏幕空间对所有像素中心进行“是否在三角形内部”这个函数的采样

采样时,会出现一些“瑕疵”Artifacts

出现这些Artifacts的原因 ——信号变化太快而采样慢

<滤波Filter>

简单理解:把特定的某些频率去掉

<傅里叶变换>可以把时域变为频域,还有逆傅里叶变换

高通滤波(边界变化明显,所以留下了边界)

低通滤波(低频信号留了下来)

 <图形学中的卷积——信号在周围的区域做一个平均>

 时域卷积==频率相乘

 这张图也验证了上边的,低通滤波模糊效果

走样,在频率的角度上看,就是频率的频谱在搬移时发生了混合

像素密集,就意味着采样密集,搬移间隔大,就不容易走样

 【反走样】

增加采样率(这是从根本上解决问题,但是现实中也不可能改变分辨率。。)

先进行模糊,再采样(先采取低通滤波,再采样)

如上图,用正方形的滤波去掉高频分量,再采样就不会出现混叠了

【SSAA-超采样反走样(Super Sampling AA)】

如果有限离散像素点逼近结果不好,那么我们用更多的采样点去逼近不就会得到更好的结果了吗?所以根据这个思想我们可以把原来的每个像素点进行细分,比如下例中,我们讲每个像素点细分成了4个采样点

把每个像素点内部所细分的采样点的颜色值全部加起来再求均值,作为该像素点的抗走样之后的颜色值

 

 靠近三角形边缘的像素点有的变淡了,从宏观角度来看的话,这个锯齿就会变得不那么明显了

【多采样反走样(Multi-Sampling AA)】

MSAA的做法也很容易理解,我们依然同样会分采样点,但是只会去计算究竟有几个采样点会被三角形cover,计算颜色的时候只会利用像素中心坐标计算一次颜色(即所有的信息都会被插值到像素中心然后取计算颜色)

【作业2】

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]
    //判断bounding Box内的像素是否在三角形内
    Vector2f p;
    p << x,y;   //像素的中心点
    //(head是取前2个数)
    Vector2f AB = _v[1].head(2) - _v[0].head(2);
    Vector2f BC = _v[2].head(2) - _v[1].head(2);
    Vector2f CA = _v[0].head(2) - _v[2].head(2);

    Vector2f AP = p - _v[0].head(2);
    Vector2f BP = p - _v[1].head(2);
    Vector2f CP = p - _v[2].head(2);

    //叉乘,判断是否在三角形内
    return AB[0] * AP[1] - AB[1] * AP[0] > 0
        && BC[0] * BP[1] - BC[1] * BP[0] > 0
        && CA[0] * CP[1] - CA[1] * CP[0] > 0;
}
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 tup = computeBarycentric2D((float)x + pos[i][0], (float)y + pos[i][1], t.v);
                        float alpha;
                        float beta;
                        float gamma;
                        std::tie(alpha, beta, gamma) = tup;
                        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) {
                        Vector3f color = t.getColor() * count / 4.0;
                        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 tup = computeBarycentric2D((float)x + 0.5, (float)y + 0.5, t.v);
                    float alpha;
                    float beta;
                    float gamma;
                    std::tie(alpha, beta, gamma) = tup;
                    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) {
                        Vector3f color = t.getColor();
                        Vector3f point(3);
                        point << (float)x, (float)y, z_interpolated;
                        depth_buf[get_index(x, y)] = z_interpolated;
                        set_pixel(point, color);
                    }
                }
            }
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值