Games101 阶段性总结②

一、光栅化(Rasterization)

光栅化就是这么把图元画在屏幕上,即三角性的插值、采样等。
image
此为屏幕空间,你会觉得奇怪,为什么MVP之后不是已经投影了吗,不,其实MVP只是为投影做了准备,并没有画出具体画线规则等。
将上图再进行衍生
image
FOV就是我们所说的广角(垂直可视角度)
然后宽高比Aspect ratio
那么如何去利用他们的关系
image
之后我们需要把我们MVP矩阵变换而来的[-1,1]的三次方的方块转化到屏幕空间。
首先,我要定义,屏幕空间的原点是左下角(0,0)坐标,每个像素对应一个整型的(x,y),如(3,2)
image
相当于这个红色方块
但是我们有规定,像素点其实位于(x+0.5,y+0.5)处
image
那么我们如何将转化[-1,1]的三次方的方块转化到屏幕空间
image
绿线框表示将原本2的距离缩小为1;
红线框表示将我们的矩阵等同我们想要的屏幕空间大小;
蓝线表示,将我们的矩阵移动到屏幕空间规定的原点
最后得到
image

二、三角形遍历与AABB(axis-aligned bounding box)包围盒

  1. 利用叉积得到(x+0.5,y+0.5)是否在三角形内
卷积看是否在三角形内
static bool insideTriangle(int x, int y, const Vector3f* _v)
{   
    Vector3f pixel = Vector3f(x,y,1.0);
    Vector3f AB = _v[0].head(3) - _v[1].head(3);
    Vector3f BC = _v[1].head(3) - _v[2].head(3);
    Vector3f CA = _v[2].head(3) - _v[0].head(3);

    Vector3f AP = _v[0].head(3) - pixel;
    Vector3f BP = _v[1].head(3) - pixel;
    Vector3f CP = _v[2].head(3) - pixel;

    if ((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) || (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)) {
        return true;
    }
    else
        return false;
    
}
  1. 为了减少内耗,以及更快速画出图像,引入包围盒bounding box
取得3个顶点,并比较其x,y值,画出包围盒
    auto v = t.toVector4();
    Vector3f triangele[3];
    for (int i = 0; i < 3; i++) {
        triangele[i] = Vector3f(v[i].x(), v[i].y(), v[i].z());
    
    }
    float minx = std::min(std::min(v[0].x(), v[1].x()), v[2].x());
    float maxx = std::max(std::max(v[0].x(), v[1].x()), v[2].x());
    float miny = std::min(std::min(v[0].y(), v[1].y()), v[2].y());
    float maxy = std::max(std::max(v[0].y(), v[1].y()), v[2].y());

image

采样出来我们会得到一个有锯齿的三角形图案,这我们就的引入反走样(Anti-Aliasing)技术了


在早期工业领域,是通过傅里叶变换来进行思考的
当时域采样频率越疏时候,频域就越密集,而采样的过程就是重复原始的被采样的信号的频域频谱,如果越密集,则会发生相交,这就是锯齿的由来,那么我们在不能提高采样频率的情况,就选一个低通滤波来对被采样频谱进行过滤,此时就会得到不相交的采样频谱,再逆变换回时域,这就是模糊后再采样。


传统方法是利用卷积(Convolution)的形式对图像进行模糊操作后再采样
还有更为细致的采用多个采样点(MSAA)
FXAA 换锯齿边界,不用卷积技术
TAA 复用上一帧的像素值,就是将判断像素值是否在三角形内,进行筛选的过程


三、深度测试

最后要做一个深度测试,这是对一个不透明物体而言得,如果是透明物体,则无深度测试(z-buff)
z-buff是对每个像素点而言得,对深度缓存中的值进行比较,z<深度缓存,则替换

点击查看代码
for (int x=minx; x<maxx;x++) {
        for (int y=miny; y<maxy;y++ ) {
            if (insideTriangle(x + 0.5, y + 0.5, triangele)) {
                float alpha;
                float beta;
                float gamma;
                std::tie(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;
                if (z_interpolated <depth_buf[get_index(x,y)] ) 
                {
                    depth_buf[get_index(x, y)] = z_interpolated;
                    set_pixel(Vector3f (x, y , 1.0), t.getColor());
                }

            }
        }

    }
posted @ 2022-01-30 22:28  Ariaaaaa  阅读(14)  评论(0)    收藏  举报