一、抗锯齿
渲染出来的物体放大后,会在边界上看到明显的阶梯状,产生这种结果的原因是因为采样点设置的比较少,采样的颜色结果在边界处发生了突变。
这种现象称为走样,而我们需要利用一些抗锯齿技术(反走样)帮助我们缓解这种现象,产生更平滑的边缘。
超采样抗锯齿
(SSAA)是其中之一,原理是预先提升比正常分辨率更高的分辨率来渲染场景,在正式渲染的时候,分辨率会被下采样至正常的分辨率。虽然可以解决走样的问题但带来了更大的性能开销。
二、多重采样(MSAA)
多重采样基于OpenGl光栅器的改进。
在将一个图元的所有顶点作为输入后,要将其转换为一系列的片段。顶点坐标理论上可以取任意值,但片段不行。
我们在每一个屏幕像素中心定义了一个采样点,用来决定这个三角形是否遮盖了这个像素。
然后采样点在三角形内,那么这个片段会被着色。于是,结果就造成了边缘的不光滑。
而多重采样的原理就是基于这个问题提出的。
重采样所做的正是将单一的采样点变为多个采样点。我们不再使用像素中心的单一采样点,取而代之的是以特定图案排列的4个子采样点。我们将用这些子采样点来决定像素的遮盖度。当然,这也意味着颜色缓冲的大小会随着子采样点的增加而增加。
最后的颜色会根据像素中采样点覆盖的个数而变化。
三、OpenGL中的MSAA
由上可知,MSAA需要在每一个像素中存储大于1颜色值的颜色缓冲。所以需要一个新的缓冲类型,我们称为多重采样缓冲。
- 在创建窗口之前,提示GLFW使用一个包含4个样本的多重采样缓冲
glfwWindowHint(GLFW_SAMPLES, 4);
- 启用多重采样
glEnable(GL_MULTISAMPLE);
剩下的就交给OpenGl了。
四、离屏MSAA
如果我们想要使用我们自己的帧缓冲来进行离屏渲染,那么我们就必须手动生成多重采样缓冲。
有两种方式可以创建多重采样缓冲,将其作为帧缓冲的附件:纹理附件和渲染缓冲附件。
1.多重采样纹理附件
- 使用glTexImage2DMultisample 来替代 glTexImage2D 创建一个支持储存多个采样点的纹理,纹理目标是GL_TEXTURE_2D_MULTISAPLE。
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
第二个参数samples
设置的是纹理所拥有的样本个数,GL_TRUE
代表每个纹素使用相同的样本位置以及相同数量的子采样点个数。
- 使用glFramebufferTexture2D将多重采样纹理附加到帧缓冲上。
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0);
当前绑定的帧缓冲现在就有了一个纹理图像形式的多重采样颜色缓冲。
2.多重采样渲染缓冲对象
- 在指定渲染缓冲的内存存储时,将
glRenderbufferStorage
的调用改为glRenderbufferStorageMultisample
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
渲染缓冲对象参数设置为样本数4
- 将图像位块传送(Blit)到默认的帧缓冲中,将多重采样的帧缓冲传送到屏幕上
glBindFramebuffer(GL_READ_FRAMEBUFFER, multisampledFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);