光栅化
在对顶点的 MVP 变换以及视图变换之后,我们需要将视图变换后的顶点代表的图元,如三角形、网格等等,映射到屏幕上的像素,这一过程我们称之为光栅化。
采样
采样是指在连续领域中获取离散样本的过程,涉及将连续信号(比如声音、图像或其他信号)在时间或空间上按照一定间隔采集成离散的数据点。在光栅化中我们同样可以定义采样方法,即采样条件是,当像素在三角形内时我们采样。
定义一个二值函数,位于三角形内则采样,位于三角形外则不采样。(利用向量叉积的方法判断):
反走样 (Antialiasing)
利用简单的采样我们得到结果可以发现,得到的图像在边缘有明显的锯齿感 (Jaggies) ,反走样的目的就是消除锯齿。
反走样方法一:采样前滤波 (Pre-Filtering)
走样的根本原因是,采样频率跟不上信号频率。采样前滤波是通过降低实际的信号频率而达到反走样的目的。
采样前滤波是指在当顶点代表的图元在采样之前,对其进行模糊处理(频域上进行低通滤波或者是在时域上进行卷积),随后再进行采样。
反走样方法二:超采样 (MSAA)
与采样前滤波不同,超采样通过提高采样频率来达到反走样的目的。超采样的原理就是在一个像素内的多个位置进行采样,记录这些在像素内部且位于三角形内的点,计算这些点在像素内的占比,占比的结果即为该像素最终的采样结果。
传统的点采样:
超采样:
GAMES101 作业2
作业要求
(1)创建三角形的 2 维 bounding box。
(2)遍历此 bounding box 内的所有像素(使用其整数索引)。然后,使用像素中。
心的屏幕空间坐标来检查中心点是否在三角形内。
(3)如果在内部,则将其位置处的插值深度值 (interpolated depth value) 与深度缓冲区 (depth buffer) 中的相应值进行比较,如果当前点更靠近相机,请设置像素颜色并更新深度缓冲区。
void rst::rasterizer::rasterize_triangle(const Triangle& t) {
auto v = t.toVector4();
//1.寻找三角形的最小包围盒
float min_x = std::floor(std::min(v[0].x(), std::min(v[1].x(), v[2].x())));
float max_x = std::ceil(std::max(v[0].x(), std::max(v[1].x(), v[2].x())));
float min_y = std::floor(std::min(v[0].y(), std::min(v[1].y(), v[2].y())));
float max_y = std::ceil(std::max(v[0].y(), std::max(v[1].y(), v[2].y())));
for (int i = min_x; i < max_x; i++)
{
for (int j = min_y; j < max_y; j++)
{
//2.判断bounding box的像素是否位于三角形内
if (insideTriangle(i + 0.5, j + 0.5, t.v))
{
//3.获取插值深度值
auto tup = computeBarycentric2D((float)i + 0.5, (float)j + 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;
//深度测试,通过便添加颜色,并同时将深度存入缓存
//将当前像素的深度值z_interpolated与深度缓冲区中的值进行比对,如果小,则填充颜色,并更新深度缓冲区
if (depth_buf[get_index(i, j)] > z_interpolated)
{
//深度存入缓存
depth_buf[get_index(i, j)] = z_interpolated;
Vector3f point = { (float)i,(float)j,z_interpolated };
Vector3f color = t.getColor();
//添加颜色
set_pixel(point, color);
}
}
}
}
}