1
$\begingroup$

The setup

I have a working bloom shader implemented which creates a fbo with two textures attached to it.

  1. The first texture holds the entire scene
  2. The other only displays objects which are supposed to be bloomed in a postprocessing (ping pong) step

At the and the end both textures are added.

Here is the code which creates the according fbo:

    void CreateHdrBloomFBO(GLuint &hdr_fbo, GLuint *color_buffers, GLuint *pingpong_fbo, GLuint *pingpong_color_buffers, GLuint &rbo_depth, float width, float height)
    {
        glGenFramebuffers(1, &hdr_fbo);
        glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo);
        glGenTextures(2, color_buffers);

        for (unsigned int i = 0; i < 2; i++)
        {
            glBindTexture(GL_TEXTURE_2D, color_buffers[i]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, color_buffers[i], 0);
        }

        glGenRenderbuffers(1, &rbo_depth);
        glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
        GLuint attachments[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
        glDrawBuffers(2, attachments);

        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            std::cout << "CORE::CREATE_FRAMEBUFFER_FAIL - Failed creating HDR/BLOOM buffers." << std::endl;
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        glGenFramebuffers(2, pingpong_fbo);
        glGenTextures(2, pingpong_color_buffers);
        for (unsigned int i = 0; i < 2; i++)
        {
            glBindFramebuffer(GL_FRAMEBUFFER, pingpong_fbo[i]);
            glBindTexture(GL_TEXTURE_2D, pingpong_color_buffers[i]);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pingpong_color_buffers[i], 0);

            if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
                std::cout << "CORE::CREATE_FRAMEBUFFER_FAIL - Failed creating HDR/BLOOM-pingpong buffers." << std::endl;
        }
    }

So my renderloop looks something like this.

// 1. Bind fbo
// 2. Render scene 
// 3. Blur cube and earth fragments with two-pass Gaussian Blur
bool horizontal = true, first_iteration = true;
unsigned int amount = 10;
blur_shader.use();
for (unsigned int i = 0; i < amount; i++)
{
    glBindFramebuffer(GL_FRAMEBUFFER, pingpong_fbo[horizontal]);
    blur_shader.set_int("horizontal", horizontal);
    // Note on the first iteration I take the second texture from above, which holds the objects which are supposed to get bloomed.
    glBindTexture(GL_TEXTURE_2D, first_iteration ? color_buffers[1] : pingpong_color_buffers[!horizontal]);
    core::RenderQuad(&quad_geometry);
    horizontal = !horizontal;
    if (first_iteration)
        first_iteration = false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// 4. Combine normal and bloom textures
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
bloom_final_shader.use();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, color_buffers[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, pingpong_color_buffers[!horizontal]);
bloom_final_shader.set_int("bloom", use_bloom);
bloom_final_shader.set_float("exposure", exposure);
core::RenderQuad(&quad_geometry);

This is what the output of the scene render looks like. The are the scene and the blooming targets:

enter image description here

In the first blooming step the correct image is passed and "ping ponged" afterwards.

enter image description here

The final image:

enter image description here

The problem

I want to implement antialiasing on top of the given process. Therfore I create a multisample fbo which also holds two textures:

void CreateMsaaFBO(GLuint &target_fbo, GLuint *target_fbo_textures, GLuint &rbo_depth_stencil, float width, float height)
{
    glGenFramebuffers(1, &target_fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, target_fbo);
    glGenTextures(2, target_fbo_textures);
    for (unsigned int i = 0; i < 2; i++)
    {
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, target_fbo_textures[i]);
        glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, width, height, GL_TRUE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D_MULTISAMPLE,target_fbo_textures[i], 0);
    }
    glGenRenderbuffers(1, &rbo_depth_stencil);
    glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth_stencil);
    glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
    glBindRenderbuffer(GL_RENDERBUFFER, 0);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,rbo_depth_stencil);
    GLuint attachments[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
    glDrawBuffers(2, attachments);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "CORE::CREATE_FRAMEBUFFER_FAIL - Failed creating MSAA buffer." << std::endl;
    glBindFramebuffer(GL_FRAMEBUFFER_COMPLETE, 0);
}

So my Plan is to draw the scene as above this time using my msaa_fbo and use glBlitFramebuffer to copy antialiased textures to my original fbo:

// 1. Bind msaa_fbo
// 2. Render scene 
    glBindFramebuffer(GL_READ_FRAMEBUFFER, msaa_fbo);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, hdr_fbo);
    glBlitFramebuffer(0, 0, viewport_width, viewport_height, 0, 0, viewport_width, viewport_height,GL_COLOR_BUFFER_BIT, GL_NEAREST);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
// 3. blur bright fragments with two-pass Gaussian Blur as above
// ...

It seems that only the first texture gets copied to the hdr_fbo and therfore the entire image is bloomed.

The output of the msaa_fbo looks correct:

enter image description here

This is the glBindFramebuffer in renderdoc which seems to target only one texture (the scene):

enter image description here

That is why the input of the pingpong loop is the entire scene:

enter image description here

As far as I get it should copy both textures (scene + bloom) to my target hdr_fbo buffer. Why doesn't it? I started learning those concept, so I am not ruling out that I am missing something fundamental.

Also note that a lot of the code is taken from learnopengl.com.

$\endgroup$

1 Answer 1

4
+200
$\begingroup$

I think you misunderstood the use of glBlitFrameBuffer. When using this to blit Color Buffers, according to the docs,

One thing to keep in mind is this: when using GL_COLOR_BUFFER_BIT​, the only colors read will come from the read color buffer in the read FBO, specified by glReadBuffer. The colors written will only go to the draw color buffers in the write FBO, specified by glDrawBuffers. If multiple draw buffers are specified, then multiple color buffers are updated with the same data.

So simply speaking, when blitting color buffers, you need to specify what ReadBuffer by using glReadBuffer which takes in color attachment number when dealing with FBOs.

So in short, you can't expect to copy both the attachments or textures with a single blit call.

Also, can't you just render the anti-aliased scene once, blit this single texture to get a working copy of it usable in shaders and then extract the second texture which is essentially just the environment subtracted from it?

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.