Search code examples
opengldeferred-rendering

OpenGL implementing skybox in a deferred renderer


I am trying to figure out how to render a skybox in a deferred renderer so that it can be included in post processing effects, However my Geometry stage is in view space and unfortunately the skybox in this stage will be effected by it's position relative to the light as any object would (it behaves like large box located very far from the light source and shows up very dark). my setup without trying to incorporate the skybox in post processing is as follows:

1:(bind FBO) Render Geometry to color, normal, position FBO texture attachments (unbind FBO).

2:(bind FBO) Render the scene and calculate lighting in screen space.(unbind FBO)

3:(bind FBO) apply post processing effects (unbind FBO)

4: blit the Geometry FBO's depth buffer to the default frame buffer

5: render skybox.

I've tried to switch step 5 with 3 like this:

2:(bind FBO) Render the scene and calculate lighting in screen space.

5: render skybox

(unbind FBO)

3:(bind FBO) apply post processing effects (unbind FBO)

4: blit the Geometry FBO's depth buffer to the default frame buffer

but obviously the skybox has no depth information about the scene and renders on top of the lighting stage. And if I try to do any depth blitting between 2 and 5, I believe I am making invalid GL calls because I'm already bound to an FBO while calling

 GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, DeferredFBO.fbo_handle);
 GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, 0); // Write to default
                                                            // framebuffer or a skybox framebuffer    


    GL30.glBlitFramebuffer(0, 0, DisplayManager.Width,
            DisplayManager.Height, 0, 0, DisplayManager.Width,
            DisplayManager.Height, GL11.GL_DEPTH_BUFFER_BIT,
            GL11.GL_NEAREST);

Solution

  • Then give it the depth information it lacks.

    When you rendered your scene in step 1, you used a depth buffer. So when you draw your skybox, you need an FBO that uses that same depth buffer. But this FBO also needs to use the color image that you rendered to in step 2.

    Now, this FBO cannot be the same FBO you used in step 2. Why?

    Because that would be undefined behavior. Presumably, step 2 reads from your depth buffer to reconstruct the position (if this is not the case, then you can just attach the depth buffer to the FBO from step 2. But then again, you're also wasting tons of performance). But that depth buffer is also attached to the FBO. And that makes it undefined behavior. Even if you're not writing to the depth, it is still undefined under OpenGL.

    So you will need another FBO, which has the depth buffer from step 1 with the color buffer from step 2.

    Unless you have access to OpenGL 4.5/ARB_texture_barrier/NV_texture_barrier. With that feature, it becomes defined behavior if you use write masks to turn off writes to the depth buffer. All you need to do is issue a glTextureBarrier before performing step 2. So you don't need another FBO if you have that.

    In either case, keep the depth test enabled when rendering your skybox, but turn off depth writing. This will allow fragments behind your actual world to be culled, but the depth of the skybox fragments will be infinitely far away.