OpenGL - How to draw to a multisample framebuffer and then use the result as a normal texture?

北城以北 提交于 2019-12-11 08:05:50

问题


I'm developing a little gamedev library. One of the elements of this library is a Canvas (offscreen drawing area), which is implemented through an OpenGL framebuffer. So far, everything's been good, I generate a texture, attach it to a framebuffer, render to it, then use the framebuffer's texture as Texture2D.

Now, I'd like to add antialiasing to my library, so I'd like to be able to set multisampling on a Canvas. Now I'm confused because I've found that you need to alter shaders to use multisample textures and so on.

So, what should I do to enable multisampling for my framebuffers so that I minimize changing the rest of the code of the library? I'd like to just use the rendering result as a regular Texture2D if possible.


回答1:


Just to make sure that there's no confusion. You can't just create a texture that is x times bigger and then wish that filters will do the magic. Because GL_LINEAR, etc. only averages the four texels closest to the center of the pixel being textured.

To create a multisample texture you'd use glTexImage2DMultisample() (available in core since 3.2). You'd set it up like this.

glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, tex);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, false);

It should be self-explanatory as samples being the amount of samples in the multisample texture. Also change the internalformat as you please.

To attach the texture to a framebuffer you equally use glFramebufferTexture2D(). But instead of setting the textarget as GL_TEXTURE_2D you set it to GL_TEXTURE_2D_MULTISAMPLE.

glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, tex, 0);

Remember to check the status of your framebuffer.

In your shader you'll also have to use sampler2DMS to be able to access the multisample texture. However note that multisample textures work quite differently compared to regular textures. If you want to read from the texture you'll have to use texelFetch().

So if you want to sample from a multisample texture then you can't use texture() but would have to utilize texelFetch() with something like.

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;
}

Note that texelFetch() doesn't take normalized coordinates, you can circumvent this with something like:

vec2 uv = vec2(0.5, 0.5); // normalized coordinates
ivec2 texSize = textureSize(tex, 0);
ivec2 texCoord = ivec2(uv * texSize);
vec4 color = textureMultisample(tex, texCoord);

At the end of the day if you want display the crisp anti-aliased result, you'll have to blit it to the screen.

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);

If you need a multisample depth buffer then look into glRenderbufferStorageMultisample().

Also make sure that glEnable(GL_MULTISAMPLE). However today most drivers enable it by default.

Last but not least, here's a few other Stack Overflow/Exchange question related to multisampling that you might find interesting.

  • Filtering
  • texelFetch() vs texture()
  • Multisample Window Buffer


来源:https://stackoverflow.com/questions/42878216/opengl-how-to-draw-to-a-multisample-framebuffer-and-then-use-the-result-as-a-n

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!