2
votes

I'm trying to create one FBO to draw a 3D scene on and another FBO to draw a HUD on. I then try to combine these two FBOs by blitting the 3D scene to the default FBO and then blitting the HUD to the default FBO.

Each FBO created has the same dimensions as the window, and has a RBO for both the color attachment and the depth attachment.

What I expect to happen is that the blit of the 3D FBO would fill the depth buffer of the default FBO with data from the 3D depth RBO while drawing the contents of the 3D color RBO. Then the second blit, the HUD, would draw the HUD color RBO data into the default FBO where the HUD depth RBO is GL_LEQUAL the default FBO's depth data.

Side Note

I understand that what I probably want is to clear the HUD with a color that has no alpha (currently I clear with <1.0f, 0.0f, 1.0f, 0.0f>) and then disable depth test and blit the HUD to the default FBO. This would make sure that the HUD is always on top. I intend to do this, but I need to make the depth check version work first.

What is currently happening is that the 3D FBO is drawing to the scene and then the HUD FBO draws completely over it. The spots where there should be a transparent clear color for the background aren't clear either. They draw over the 3D scene covering it up completely.

Am I missing something or not understanding the FBO blitting? Is it possible the depth check is working correctly, but the clear color alpha channel is not being blended?

An OpenGL call log for a single frame can be found here:
http://fpaste.org/84040/

Program Details

  • OpenGL Context Version: 4.0
  • GLX Window Color Space: RGBA8
  • GLX Window Depth Size: 24
  • GLX Window Stencil Size: 8

Development System Details

  • Operating System: Ubuntu 12.04 LTS
  • Graphics Card: ATI Radeon HD 5750
  • Driver Version: 13.25.5

Blit Code

public void blit(int dstX = 0, int dstY = 0,
                 int dstWidth = 0, int dstHeight = 0,
                 uint targetFrameBuffer = 0)
{
   int mask;

   // Start out with nothing set.
   mask = 0;

   // See if we should blit the color buffer.
   if (color_buffer != null)
   {
      mask |= GL_COLOR_BUFFER_BIT;
   }

   // See if we should blit the depth buffer.
   if (depth_buffer != null)
   {
      mask |= GL_DEPTH_BUFFER_BIT;
   }

   // See if we should blit the stencil buffer.
   if (stencil_buffer != null)
   {
      mask |= GL_STENCIL_BUFFER_BIT;
   }

   // Make sure some mask was set before anything is done.
   if (mask != 0)
   {
      // Enable depth writing if a depth buffer is available.
      if (depth_buffer != null)
      {
         // Enable depth writing.
         glDepthMask(GL_TRUE);
      }

      // Bind the reading and drawing buffers.
      glBindFramebuffer(GL_READ_FRAMEBUFFER, reference);
      glReadBuffer(GL_COLOR_ATTACHMENT0);
      glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFrameBuffer);

      // If the target buffer is the default FBO,
      // then render to the back one.
      if (targetFrameBuffer == 0)
      {
         glDrawBuffer(GL_BACK);
      }

      glBlitFramebuffer(0, 0, width, height,
                        dstX, dstY, dstWidth, dstHeight,
                        mask, GL_NEAREST);

      // Unbind the buffers.
      glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
      glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

      // Disable depth writing if it was enabled earlier.
      if (depth_buffer != null)
      {
         // Disable depth writing.
         glDepthMask(GL_FALSE);
      }
   }
}
1
I wanted to correct something in your code comments: glDepthMask (GL_TRUE) does not enable depth testing, that enables depth writes. You can have depth testing enabled at the same time as depth writes are disabled. On the other hand (and this is not related to your question), you cannot write to the depth buffer without depth testing enabled (if you want to write unconditionally you need to set a depth function of GL_ALWAYS).Andon M. Coleman
You are correct. I have added the glEnable(GL_DEPTH_TEST) and glDisable(GL_DEPTH_TEST) calls. This now causes nothing to show up in the drawing area. I will test this further and post a follow up.Jason Smith
It is also important to point out that glBlitFramebuffer (...) performs no pixel testing of any sort. Enabling or disabling the depth test is pointless, now that I better understand what you are actually expecting to happen. Blitting just copies one or more buffers from a source framebuffer to a destination, it may perform filtering but it does no depth/stencil testing.Andon M. Coleman

1 Answers

5
votes

glBlitFramebuffer just copies a block of pixels from one buffer to another. It doesn't use the depth buffer to accept or reject pixels from the source buffer.

You can do what you want by drawing a quad using your HUD texture and depth buffer (assuming you are binding a depth texture to your HUD FBO). You will need to write the value of the depth texture to gl_FragDepth in the fragment shader.

The same thing is true if you use alpha instead (as you say you intend to do), except you will just be blending using the alpha value of your HUD FBO. This is the better solution as it does away with the HUD depth buffer.