How to apply GLFW anti-aliasing to a framebuffer?

Started by Andrew_3ds, June 16, 2015, 18:00:20

Previous topic - Next topic

Andrew_3ds

The anti-aliasing that I set by using the glfwHint() call used to work on my rendering engine, but I just started rendering to a texture for post-processing, and then just drew that on a quad that fits the screen. Now that I'm not drawing my 3D scene on the main buffer, I think that it's not applying the anti-aliasing to it anymore. How do I make it render to the secondary buffer instead of the main one?

Kai

If you want to render to a Framebuffer Object and use multisampling, you need to create a multisampled texture and depth buffer that you attach as color attachment and depth/stencil attachment respectively to render to.
Just google "OpenGL multisampled fbo" which will bring you this opengl.org wiki page as well as this stackoverflow.com thread.
After you rendered to the FBO, you need to blit the result to the window framebuffer, which will do the sample resolution. This is shown on that opengl.org wiki page.
You also do not need to enable multisampling on the window's OpenGL context (via the window hint) anymore. That has then no effect anymore.

Andrew_3ds

When exactly do I do the blitting? I tried putting it in a few different places but it's just rendering the last bound texture instead of the FBO's texture.

Kai

Have a look at this shiny new demo. :)

Since you mentioned that you want to do postprocessing on the rendered image, there are now two ways:
- either use the multisampled color texture (which you can sample via sampler2DMS and not sampler2D)
- or blit the multisampled FBO to another offscreen FBO, which is not multisampled and then do the postprocessing on the second FBO's color texture

Andrew_3ds

When I bind my framebuffer texture to the screen do am I supposed to use GL_TEXTURE_2D or GL_TEXTURE_2D_MULTISAMPLE? I have done what the demo has but for some reason it's still not correctly binding the FBO's texture.

This is what I'm using to render it:
public static void prepareFramebufferRender() {
        //Bind the framebuffer to a texture
        framebuffer.bind();
        glClearColor(GameStructure.currentCell.skyColor.x, GameStructure.currentCell.skyColor.y, GameStructure.currentCell.skyColor.z, 1);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glEnable(GL_DEPTH_TEST);
    }

    public static void render() {
        prepareFramebufferRender();

        if(!framebuffer.isComplete()) {
            Console.errMsg("ERROR: Framebuffer not complete!");
        }

        drawScene();
        prepareFramebufferDraw();

        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);
        glBindVertexArray(quadVAO.getVaoId());
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, framebuffer.getTexAttachmentId());
        frameShader.start();
        glDrawElements(GL_TRIANGLES, quadVAO.getvAmount(), GL_UNSIGNED_INT, 0L);
        frameShader.stop();
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
        glBindVertexArray(0);

        drawGUI();
    }

    private static void prepareFramebufferDraw() {
        framebuffer.unbind(); //Done rendering to framebuffer; unbind, start rendering to main buffer again
        glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer.getFbo());
        glBlitFramebuffer(0,0,GameStructure.Window.getWidth(),GameStructure.Window.getHeight(),0,0,
                GameStructure.Window.getWidth(),GameStructure.Window.getHeight(),GL_COLOR_BUFFER_BIT, GL_NEAREST);
        glClearColor(0.7f,0.7f,0.7f,1);
        glClear(GL_COLOR_BUFFER_BIT);
    }


public Framebuffer() {
        int w,h;
        w = GameStructure.Window.getWidth();
        h = GameStructure.Window.getHeight();

        this.FrameWidth = w;
        this.FrameHeight = h;

        int texId = glGenTextures();
        int rbo = glGenRenderbuffers();
        int fbo = glGenFramebuffers();

        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texId);
        glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, Settings.antiAlias, GL_RGBA, w, h, true);

        glBindRenderbuffer(GL_RENDERBUFFER, rbo);
        glRenderbufferStorageMultisample(GL_RENDERBUFFER, Settings.antiAlias, GL_DEPTH24_STENCIL8, w, h);

        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texId, 0);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo);

        if(!isComplete()) {
            Console.errMsg("Framebuffer not complete");
        }
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
        glBindRenderbuffer(GL_RENDERBUFFER, 0);

        this.fbo = fbo;
        this.texId = texId;
        this.rbo = rbo;
    }

Kai

When using the GL_TEXTURE_2D_MULTISAMPLE texture and binding it, you must also use that same target with glBindTexture, as you did.
You also must make sure that you access it via a sampler2DMS within the shader.

Additionally, there is now a demo that does the resolving with a blit into a single-sampled FBO, so that you can access the final resolved single-sampled texture: See this demo