为了避免混淆,你不能仅仅创建一个x倍大小的纹理,然后希望滤波器能够自动处理。因为GL_LINEAR
等只会对最靠近被纹理化像素中心的四个纹素进行平均。
要创建一个多重采样纹理,你需要使用glTexImage2DMultisample()
(自3.2版本起已经成为核心功能)。你可以按照以下方式设置它。
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, false);
这段文字的意思是,samples
代表多重采样纹理中的采样数量,internalformat
可以根据需要进行更改。
要将纹理附加到帧缓冲区,同样使用glFramebufferTexture2D()
。但是,将textarget
设置为GL_TEXTURE_2D_MULTISAMPLE
,而不是GL_TEXTURE_2D
。
glBindFramebuffer(GL_FRAMEBUFFER, fbo)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0)
记得检查你的帧缓冲状态。
在着色器中,您还需要使用sampler2DMS
才能访问多重采样纹理。但请注意,与常规纹理相比,多重采样纹理的工作方式有很大不同。如果要从纹理中读取,则必须使用texelFetch()
。
因此,如果您想从多重采样纹理中进行采样,则不能使用texture()
,而是必须利用texelFetch()
,例如:
uniform int texSamples;
uniform sampler2DMS tex;
vec4 textureMultisample(sampler2DMS sampler, ivec2 coord)
{
vec4 color = vec4(0.0);
for (int i = 0; i < texSamples; i++)
color += texelFetch(sampler, coord, i);
color /= float(texSamples);
return color;
}
请注意,
texelFetch()
不接受归一化坐标,您可以通过以下方式规避此问题:
vec2 uv = vec2(0.5, 0.5)
ivec2 texSize = textureSize(tex, 0)
ivec2 texCoord = ivec2(uv * texSize)
vec4 color = textureMultisample(tex, texCoord)
如果你想要显示清晰的抗锯齿结果,最终你需要将其复制到屏幕上。
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glDrawBuffer(GL_BACK);
glBlitFramebuffer(0, 0, src_width, src_height, 0, 0, dst_width, dst_height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
如果需要多重采样深度缓冲区,请查看
glRenderbufferStorageMultisample()
。
此外,请确保启用
glEnable(GL_MULTISAMPLE)
。然而,现在大多数驱动程序默认启用它。
最后,这里有一些与多重采样相关的Stack Overflow/Exchange问题,你可能会感兴趣。
sampler2DMS
和texelFetch()
/textureMultisample()
,那么您可以在着色器中像使用普通纹理一样使用它。但是除此之外,如果您想将多重采样纹理转换为普通纹理,则需要在两个帧缓冲区之间进行传输。 - vallentinglGenerateMipmap()
。超级采样和典型的多重采样之间的实际区别在于后者由于每个片段而不是每个样本执行片段着色器而更快(这并不总是正确的,请参见glMinSampleShading()
)。 - Ruslan