我正在开发一个小型的gamedev库。该库的一个元素是Canvas(屏幕外绘图区域),它通过OpenGL帧缓冲实现。到目前为止,一切都很好,我生成一个纹理,将它附加到一个帧缓冲区,渲染到它,然后使用framebuffer的纹理作为Texture2D。
现在,我想在我的库中添加抗锯齿,所以我希望能够在Canvas上设置多重采样。现在我很困惑,因为我发现你需要改变着色器以使用多重采样纹理等等。
那么,我该怎样做才能为我的帧缓冲区启用多重采样,以便最大限度地减少更改库的其余代码?如果可能的话,我想将渲染结果用作常规的Texture2D。
答案 0 :(得分:3)
只是为了确保没有混淆。你不仅可以创建一个x倍大的纹理,然后希望过滤器能够发挥魔力。因为GL_LINEAR
等只有averages the four texels closest to the center of the pixel being textured。
要创建多重采样纹理,您需要使用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
,而是将其设置为GL_TEXTURE_2D_MULTISAMPLE
。
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); // normalized coordinates
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问题。