当前位置:网站首页>GAMES-101-个人总结归纳-Rasterization

GAMES-101-个人总结归纳-Rasterization

2022-06-22 01:20:00 风之涯角

(注:此文以个人知识框架为基础拓开,为方便后期回顾,在保留原课程内容框架的基础上,个别概念的介绍可能过于简单,感兴趣读者可到 GAMES 平台深入学习)

目录

Rasterization

Different raster displays(略)

Rasterizing a triangle

Antialiasing(反走样)

Sampling theory

Antialiasing in practice

Occlusions and Visibility(深度缓冲)

Visibility / occlusion - Z-buffering

作业2

题目简单介绍

核心代码

1.判断像素点是否在三角形内:

2.对场景内的三角形做 z-buffer 深度缓冲

3.MSAA处理:

效果图


Rasterization

Different raster displays(略)

Rasterizing a triangle

(三角形生万物~~)

判断点在三角形内:

做叉积,结果同正或同负,表示点在三条边同侧,即点在三角形内。

注:cross(P0Q,P0p1) -> left;cross(P1Q,P1P2) -> left; cross(P2Q,P2P0) -> right

Antialiasing(反走样)

Sampling theory

  1. (黑话)artifacts:一切不准确,看起来不太对的结果
  2. 采样的存在的问题:

        Jaggies(锯齿)

        Moiré Patterns(摩尔纹):去掉图片的奇数行和奇数列后按照图片原尺寸显示。

        

         wagonWagon Wheel Illusion(转轮错觉):人眼在时间上采样跟不上转速,而产生的转轮反向旋转的错觉。

        

        3.傅里叶变换,过程不赘述,这里主要是为了给处理 aliasing 的两种方案提供理论基础:

        (1)提高采样率(采样的本质是对频域上频谱的重复搬移,时域上采样越稀疏,对应频域上频谱上的搬移越密集,频谱混叠的部分越多,于是产生的 aliasing 越明显)

  •         (2)反走样:先做模糊(对信号做低通滤波,拿掉高频信号),再采样。换句话说,既然你频谱混叠会产生 aliasing 那我就把混丢部分(高频信号)给你拿掉: 

Antialiasing in practice

  • MSAA(Multi-Sample Anti-Aliasing)/ Supersampling:在一个像素内用更多采样点进行超采样。

        

  •  业内反走样里程碑:

        (1)FXAA (Fast Approximate AA);快速近似抗锯齿:在图像层面对锯齿做后期处理。

        (2)TAA (Temporal AA):一种基于时间的优化,当前帧复用上一帧像素的值(在 RTRT 也有相关应用)。

Occlusions and Visibility(深度缓冲)

Visibility / occlusion - Z-buffering

  • 概念:以由远到近的顺序对场景中的物体的 Z 值 做深度缓冲,同像素,近物覆盖远物。
  • 开销:需要一个额外的 buffer,颜色值存 framebuffer;深度值存 depth buffer(z-buffer)。
  • other:z-buffer 无法处理透明物体
  • Algorithm:complex:O(n)

作业2

作业2原链接

题目简单介绍

基于作业1空间转换的基础上,光栅化多个三角形,并对三角形内的像素进行深度插值处理,并对结果 antialiasing.

核心代码

1.判断像素点是否在三角形内:

/// <summary>
/// 判断像素点是否在三角形内
/// </summary>
/// <param name="x">像素点 x</param>
/// <param name="y">像素点 y</param>
/// <param name="_v">三角形三个顶点</param>
/// <returns></returns>
static bool insideTriangle(float x, float 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 x1 = _v[0];
    Eigen::Vector3f x2 = _v[1];
    Eigen::Vector3f x3 = _v[2];

    // 三角形三边对应向量
    Eigen::Vector3f x1x2;
    Eigen::Vector3f x2x3;
    Eigen::Vector3f x3x1;
    x1x2 = { x2.x() - x1.x(), x2.y() - x1.y(), 0 };
    x2x3 = { x3.x() - x2.x(), x3.y() - x2.y(), 0 };
    x3x1 = { x1.x() - x3.x(), x1.y() - x3.y(), 0 };

    // 像素点与三角形三顶点相连对应向量
    Eigen::Vector3f x1p;
    Eigen::Vector3f x2p;
    Eigen::Vector3f x3p;

    x1p ={ x - x1.x(), y - x1.y(), 0};
    x2p = { x - x2.x(), y - x2.y(), 0 };
    x3p = { x - x3.x(), y - x3.y(), 0 };

    // 向量叉乘,取z轴判断正负
    float crs1 = x1x2.cross(x1p).z();
    float crs2 = x2x3.cross(x2p).z();
    float crs3 = x3x1.cross(x3p).z();
    return (crs1 > 0 && crs2 > 0 && crs3 > 0) || (crs1 < 0 && crs2 < 0 && crs3 < 0);
}

2.对场景内的三角形做 z-buffer 深度缓冲

/// <summary>
/// Screen space rasterization
/// </summary>
/// <param name="t">the triangle need to rasterize</param>
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();

    // compute the bounding box
    int max_x = MAX(v[0].x(), MAX(v[1].x(), v[2].x()));
    int max_y = MAX(v[0].y(), MAX(v[1].y(), v[2].y()));
    
    int min_x = MIN(v[0].x(), MIN(v[1].x(), v[2].x()));
    int min_y = MIN(v[0].y(), MIN(v[1].y(), v[2].y()));

    for (int x1 = min_x; x1 <= max_x; x1++) {
        for (int y1 = min_y; y1 <= max_y; y1++) {
            if (insideTriangle(x1 + 0.5, y1 + 0.5,t.v)) {
                // 计算点在三角形内的中心坐标,关于下面的插值算法可参考:https://zhuanlan.zhihu.com/p/140926917
                auto [alpha, beta, gamma] = computeBarycentric2D(x1, y1, 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 (depth_buf[get_index(x1, y1)] > z_interpolated) {
                    depth_buf[get_index(x1, y1)] = z_interpolated;// 更新 z-buffer 深度值
                    set_pixel({ (float)x1,(float)y1,1 }, t.getColor()); // 更新 frame-buffer 颜色值
                }
            }
        }
    }
}

3.MSAA处理:

/// <summary>
/// Screen space rasterization(super sampling)
/// </summary>
/// <param name="t">the triangle need to rasterize</param>
void rst::rasterizer::super_rasterize_triangle(const Triangle& t) {
    auto v = t.toVector4();

    // compute the bounding box
    int max_x = MAX(v[0].x(), MAX(v[1].x(), v[2].x()));
    int max_y = MAX(v[0].y(), MAX(v[1].y(), v[2].y()));

    int min_x = MIN(v[0].x(), MIN(v[1].x(), v[2].x()));
    int min_y = MIN(v[0].y(), MIN(v[1].y(), v[2].y()));

    for (int x1 = min_x; x1 <= max_x; x1++) {
        for (int y1 = min_y; y1 <= max_y; y1++) {
            int inner = 0;
            // 一个像素16个点进行超采样
            for (int sx = 0; sx < 4; sx++) {
                for (int sy = 0; sy < 4; sy++) {
                    if (insideTriangle(x1 + 0.125 + 0.25 * sx, y1 + 0.125 + 0.25 * sy, t.v)) {
                        inner++;
                    }
                }
            }

            if (inner > 0) {
                //计算三角形重心坐标
                auto [alpha, beta, gamma] = computeBarycentric2D(x1, y1, 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 (depth_buf[get_index(x1, y1)] > z_interpolated) {
                    depth_buf[get_index(x1, y1)] = z_interpolated;// 更新 z-buffer 深度值
                    set_pixel({ (float)x1,(float)y1,1 }, t.getColor() * (inner / 16.f));// 更新 frame-buffer 颜色值
                }

            }

        }
    }
}

效果图

1.正常光栅化

2.MSAA 处理后的效果对比:

原网站

版权声明
本文为[风之涯角]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_41346635/article/details/125325694