Games101 阶段性总结②
一、光栅化(Rasterization)
光栅化就是这么把图元画在屏幕上,即三角性的插值、采样等。

此为屏幕空间,你会觉得奇怪,为什么MVP之后不是已经投影了吗,不,其实MVP只是为投影做了准备,并没有画出具体画线规则等。
将上图再进行衍生

FOV就是我们所说的广角(垂直可视角度)
然后宽高比Aspect ratio
那么如何去利用他们的关系

之后我们需要把我们MVP矩阵变换而来的[-1,1]的三次方的方块转化到屏幕空间。
首先,我要定义,屏幕空间的原点是左下角(0,0)坐标,每个像素对应一个整型的(x,y),如(3,2)

相当于这个红色方块
但是我们有规定,像素点其实位于(x+0.5,y+0.5)处

那么我们如何将转化[-1,1]的三次方的方块转化到屏幕空间

绿线框表示将原本2的距离缩小为1;
红线框表示将我们的矩阵等同我们想要的屏幕空间大小;
蓝线表示,将我们的矩阵移动到屏幕空间规定的原点
最后得到

二、三角形遍历与AABB(axis-aligned bounding box)包围盒
- 利用叉积得到(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;
}
- 为了减少内耗,以及更快速画出图像,引入包围盒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());

采样出来我们会得到一个有锯齿的三角形图案,这我们就的引入反走样(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());
}
}
}
}

浙公网安备 33010602011771号