1
\$\begingroup\$

I'm writing a deferred renderer, and I use two FBOs: the first one for G-buffer (color, normal, depth) and the second one for lighting (light output), so the first one has three textures bound and the second one has just one.

Now, the geometry pass works just fine and all the three textures are populated correctly. After this, I try to render a full-screen quad in the lighting pass, but nothing comes to the screen - everything is black. I've even tried to use the diffuse shader program in this pass to be sure it's not a shader problem, and it's not - nothing gets drawn no matter which shader I use.

Here's some code (I've pruned out the non-relevant code)-

G-buffer initialization

// Setup buffers and textures
// FBO initialization
geometryFboId = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.FramebufferExt, geometryFboId);

// Texture initialization
diffuseTexture = GL.GenTexture();
normalTexture = GL.GenTexture();
depthTexture = GL.GenTexture();

// Diffuse texture
GL.BindTexture(TextureTarget.Texture2D, diffuseTexture);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, scrWidth, scrHeight, 0, PixelFormat.Rgb, PixelType.UnsignedByte, IntPtr.Zero);
GL.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0Ext, TextureTarget.Texture2D, diffuseTexture, 0);

// Normal texture
GL.BindTexture(TextureTarget.Texture2D, normalTexture);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, scrWidth, scrHeight, 0, PixelFormat.Rgb, PixelType.UnsignedByte, IntPtr.Zero);
GL.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment1Ext, TextureTarget.Texture2D, normalTexture, 0);

// Depth texture
GL.BindTexture(TextureTarget.Texture2D, depthTexture);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, scrWidth, scrHeight, 0, PixelFormat.Rgb, PixelType.UnsignedByte, IntPtr.Zero);
GL.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment2Ext, TextureTarget.Texture2D, depthTexture, 0);

DrawBuffersEnum[] drawBuffers = new DrawBuffersEnum[] { DrawBuffersEnum.ColorAttachment0, DrawBuffersEnum.ColorAttachment1, DrawBuffersEnum.ColorAttachment2 };
GL.DrawBuffers(3, drawBuffers);

GL.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);

Lighting buffer initialization

lightsFboId = GL.GenFramebuffer();
GL.BindFramebuffer(FramebufferTarget.FramebufferExt, lightsFboId);
lightsTexture = GL.GenTexture();

GL.BindTexture(TextureTarget.Texture2D, lightsTexture);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, scrWidth, scrHeight, 0, PixelFormat.Rgb, PixelType.UnsignedByte, IntPtr.Zero);
GL.FramebufferTexture2D(FramebufferTarget.FramebufferExt, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, lightsTexture, 0);
DrawBuffersEnum[] drawBuffers = new DrawBuffersEnum[] { DrawBuffersEnum.ColorAttachment0 };
GL.DrawBuffers(1, drawBuffers);
GL.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);


// Setup a target texture for the render
lightingTexture = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, lightingTexture);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, scrWidth, scrHeight, 0, PixelFormat.Rgb, PixelType.UnsignedByte, IntPtr.Zero);
GL.BindTexture(TextureTarget.Texture2D, 0);

Render call

// Bind geometry pass
diffuseShader.Enable();
GL.UniformMatrix4(diffuseShader.GetUniformLocation("view"), false, ref Camera.main.modelview);
GL.UniformMatrix4(diffuseShader.GetUniformLocation("projection"), false, ref Camera.main.projection);
GL.BindFramebuffer(FramebufferTarget.FramebufferExt, geometryFboId);

// Render the scene
currentScene.Render();

// Clear shaders and framebuffer
Shader.ClearShader();
GL.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);

// Bind lighting pass
lightingShader.Enable();
GL.BindFramebuffer(FramebufferTarget.FramebufferExt, lightsFboId);
// Misc. parameter passing here

// Render a full-screen quad
quadRenderer.Render();

// Clear shaders and framebuffer
Shader.ClearShader();
GL.BindFramebuffer(FramebufferTarget.FramebufferExt, 0);

// Render output
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.ClearColor(0f, 0f, 0f, 0f);

quadRenderer.Render(gBuffer.DiffuseTexture, QuadRenderer.QuadPosition.TOP_LEFT);
quadRenderer.Render(gBuffer.DepthTexture, QuadRenderer.QuadPosition.TOP_RIGHT);
quadRenderer.Render(gBuffer.NormalTexture, QuadRenderer.QuadPosition.BOTTOM_LEFT);
quadRenderer.Render(gBuffer.LightsTexture, QuadRenderer.QuadPosition.BOTTOM_RIGHT); // Draws just black

Hopefully I didn't miss anything important here. I've checked both FBOs, and they are "complete". I've tried to pass a texture to the quad renderer, but it doesn't seem to matter. I've also tried to replace the lighting shader and lighting passes with the geometry ones, and still nothing.

\$\endgroup\$
4
  • \$\begingroup\$ Does lightsTexture remain black if you clear it with a non-black clear color in the lighting pass? \$\endgroup\$
    – msell
    Feb 13, 2013 at 6:22
  • \$\begingroup\$ Yeah, it does. I've tried to clear it to magenta in both shader and with GL.Clear(1f, 0f, 1f, 1f); with no resulting magenta screen. :/ \$\endgroup\$
    – manabreak
    Feb 13, 2013 at 7:56
  • \$\begingroup\$ Have you tried gDEBugger maybe? \$\endgroup\$ Feb 13, 2013 at 8:18
  • \$\begingroup\$ @SamHocevar No, I haven't. Maybe I should give it a try. :) \$\endgroup\$
    – manabreak
    Feb 13, 2013 at 12:14

1 Answer 1

2
\$\begingroup\$

I think I am missing something, here. The basic algorithm for deferred rendering is as follows:

bind geometry buffer
bind geometry shader
for each geometry
   render geometry

unbind geometry buffer
unbind geometry shader    

bind frame buffer    
bind light shader
bind textures from geometry buffer

for each light 
   bind/setup light
   render area of effect subsitute

unbind light shader
unbind frame buffer
unbind textures from geometry buffer

bind post processing effects shader
bind textures from frame buffer
render one full screen quad

Geometry part is probably in currentScene.render() but I am totally missing the iteration over all lights. And can't make anything of the last five lines.

A very good, but a but old article on the subject is Image Space Lighting over at gamedev.net

\$\endgroup\$
7
  • \$\begingroup\$ That's just about what I'm trying to do here. I'm using one "static" light just to test out it, but the problem doesn't lie there - even if I try only to paint everything white in the lighting pass, it doesn't do that. \$\endgroup\$
    – manabreak
    Feb 12, 2013 at 15:39
  • \$\begingroup\$ Do you expect that quadRenderer.Render(gBuffer.LightsTexture, QuadRenderer.QuadPosition.BOTTOM_RIGHT); to render the final image? Because that makes no sense to me. \$\endgroup\$
    – rioki
    Feb 13, 2013 at 9:09
  • \$\begingroup\$ Oh yea and where do you setup the light? Hopefully not in currentScene.Render();. Because that is the wrong place. \$\endgroup\$
    – rioki
    Feb 13, 2013 at 9:10
  • \$\begingroup\$ What you probably want to do is render lightingTexture. But that may not even be filled with anything if there was no actual light pass. \$\endgroup\$
    – rioki
    Feb 13, 2013 at 9:13
  • \$\begingroup\$ The light is set up in the BindForLightingPass(), it's hard-coded directional light. But that's not the case here, as I said I can't render anything, even if I try to clear the FBO with a color instead of using a shader. The whole question was about the FBO not filling up, not the lighting or the deferred rendering per se. :) \$\endgroup\$
    – manabreak
    Feb 13, 2013 at 12:17

Not the answer you're looking for? Browse other questions tagged .