OpenGL 编程/超采样
外观
在白色背景上绘制一条黑色线条时,计算机或 GPU 在最基本层面上只会确定应该将哪些像素设置为黑色。这对于水平或垂直线条非常有效。然而,如果线条是斜线,你将立即看到线条不平滑,而是锯齿状的。然而,如果我们不仅使用黑色和白色,而且还策略性地放置灰色像素,我们就可以欺骗我们的眼睛,使线条看起来更加平滑。这被称为抗锯齿。有各种方法可以对线条、其他形状甚至文本进行抗锯齿。最古老的技巧是在放大两倍的情况下绘制线条,然后将得到的黑白图像缩小到原始大小,取每个 2x2 像素组的平均值。结果图像将有 5 种灰色阴影(包括黑色和白色),并且是一个很大的改进。当然,你也可以将线条放大三倍、四倍甚至更多倍(对于 10、17 或更多种灰色阴影)。这种技术被称为超采样。它非常耗时,因为你必须渲染更大的图像,而且它只提供有限数量的阴影。然而,它最大的优点是这种技术非常简单,并且适用于 *任何* 类型的图像,无论是线条、文本还是 3D 场景。
我们可以使用累积缓冲区实现相同的技术。然而,问题是累积缓冲区不比普通的颜色缓冲区大,它的大小完全相同。相反,我们可以多次渲染同一个场景,但每次都稍微偏移一点。假设我们从以下设置模型-视图-投影矩阵并渲染帧的代码开始
glm::mat4 modelview = glm::lookAt(...);
glm::mat4 projection = glm::perspective(...);
glm::mat4 mvp = projection * modelview;
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
draw_scene();
glSwapBuffers();
如果我们想要进行 2x2 抗锯齿,我们分别将场景偏移 (0, 0)、(0.5, 0)、(0, 0.5) 和 (0.5, 0.5) 个像素。这很容易做到;在我们对顶点应用模型-视图-投影矩阵之后,我们有了屏幕坐标,其中 (0, 0) 对应于视窗的左下角,(1, 1) 对应于视窗的右上角。因此,为了偏移 (0.5, 0.5) 个像素,我们需要应用 (0.5 / w, 0.5 / h) 个单位的平移,其中 w 和 h 是视窗的宽度和高度(以像素为单位)。这就是结果
glm::mat4 modelview = glm::lookAt(...);
glm::mat4 projection = glm::perspective(...);
for(int i = 0; i < 4; i++) {
glm::vec3 shift = glm::vec3((i % 2) * 0.5 / w, (i / 2) * 0.5 / h, 0);
glm::mat4 aa = glm::translate(glm::mat4(1.0f), shift);
glm::mat4 mvp = aa * projection * modelview;
glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
draw_scene();
glAccum(i ? GL_ACCUM : GL_LOAD, 0.25);
}
glAccum(GL_RETURN, 1);
glSwapBuffers();
- 将此技术应用于任何之前的教程。
- 尝试 3x3、4x4、8x8 和 16x16 像素抗锯齿。你认为在质量上没有提升的点在哪里?
- 这真的与渲染更大的图像然后缩小它相同吗?那么小于一个像素的线条呢?
- 你可以将此技术与运动模糊有效地结合起来吗?