4
\$\begingroup\$

In my project I'm trying to implement a deferred rendering system, problem is, I can't seem to get a second FBO to work.

UPDATE 1

Here is the FBO initialization code:

/// G-Buffer FBO
GLuint gBufferFBO;
glGenFramebuffers(1, &gBufferFBO);
glBindFramebuffer(GL_FRAMEBUFFER, gBufferFBO);

GLuint depthStencilTex;
glGenTextures(1, &depthStencilTex);
glBindTexture(GL_TEXTURE_2D, depthStencilTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 1024, 768, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthStencilTex, 0);

GLuint colorTex;
glGenTextures(1, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1024, 768, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);

GLuint lightAccTex;
glGenTextures(1, &lightAccTex);
glBindTexture(GL_TEXTURE_2D, lightAccTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1024, 768, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, lightAccTex, 0);

GLuint viewNormTex;
glGenTextures(1, &viewNormTex);
glBindTexture(GL_TEXTURE_2D, viewNormTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1024, 768, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, viewNormTex, 0);

GLenum DrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2, DrawBuffers);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

if((g_RenderManager->CheckFBO()))
    return 1337; // Returns if there is an error
/// End G-Buffer FBO

/// Light Pass FBO

GLuint lightPassFBO;
glGenFramebuffers(1, &lightPassFBO);
glBindFramebuffer(GL_FRAMEBUFFER, lightPassFBO);

GLuint LPdepthStencilTex;
glGenTextures(1, &LPdepthStencilTex);
glBindTexture(GL_TEXTURE_2D, LPdepthStencilTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 1024, 768, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, LPdepthStencilTex, 0);


GLuint LPcolorTex;
glGenTextures(1, &LPcolorTex);
glBindTexture(GL_TEXTURE_2D, LPcolorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1024, 768, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, LPcolorTex, 0);

GLenum LPDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, LPDrawBuffers);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

if((g_RenderManager->CheckFBO()))
    return 1337; // Returns if there is an error
/// End Color Pass FBO

Here is my code that draws to the FBOs:

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gBufferFBO);
glViewport(0, 0, 1024, 768);
glDrawBuffers(2, DrawBuffers);  // GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

// Here I draw my geometry to the G-Buffer.

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lightPassFBO);
glViewport(0, 0, 1024, 768);
glDrawBuffers(1, LPDrawBuffers); // GL_COLOR_ATTACHMENT0
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

// Here I draw light volumes.

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glViewport(0, 0, 1024, 768);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

glBindFramebuffer(GL_READ_FRAMEBUFFER, lightPassFBO);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBlitFramebuffer(0, 0, 1024, 768, 0, 0, 1024, 768, GL_COLOR_BUFFER_BIT,     GL_NEAREST); 

Rendering to the gBufferFBO works fine, but when I try to render out different geometry with a different shader in lightPassFBO, nothing is rendered. Using either glBlitFreambuffer or just rendering to a quad, it still will not render.

And I clear each buffer before use, so that can't be the problem.

When looking in gDEbugger, it draws to my first buffer, but not my second.

Here is gDEbugger showing the first batch of geometry being successfully drawn into the first buffer: First FBO in gDEbugger

And here is gDEbugger showing that a different batch of geometry is not being drawn into the second buffer!: gDEbugger, second FBO not working

If it's worth anything, this is my shader code:

G-Buffer vertex shader

#version 330 core

smooth out vec2 vVaryingTexCoords;
smooth out vec3 vVaryingNormals;

uniform mat4 MV;
uniform mat4 MVP;

layout(location = 0) in vec3 vPos;
layout(location = 1) in vec2 vTexCoords;
layout(location = 2) in vec3 vNormals;

void main()
{
    vVaryingTexCoords = vTexCoords;
    vVaryingNormals = normalize(vec3(vec4(vNormals, 0.0) * MV));
    gl_Position = vec4(vPos, 1.0) * MVP ;
}

And my fragment shader (passes out color, spec power and normals)

#version 330 core

in vec3 vVaryingNormals;
in vec2 vVaryingTexCoords;

uniform sampler2D vTexTest;
uniform float Shininess;
uniform vec3 vColoration;

void main()
{
    vec3 normals = normalize(vVaryingNormals);

    gl_FragData[0].rgb = vColoration;
    gl_FragData[0].rgb *= texture(vTexTest, vVaryingTexCoords).xyz;
    gl_FragData[0].a = Shininess;

    gl_FragData[1].r = normals.x;
    gl_FragData[1].g = normals.y;
    gl_FragData[1].b = normals.z;
}

And my shader which should draw light volumes to my second buffer:

#version 330 core

uniform mat4 MVP;

layout(location = 0) in vec3 vPos;
layout(location = 1) in vec2 vTexCoords;
layout(location = 2) in vec3 vNormals;

void main()
{
    vec2 vVaryingTexCoords = vTexCoords;
    vec3 vVaryingNormals = vNormals;
    gl_Position = vec4(vPos, 1.0) * MVP;
}

fragment shader:

#version 330 core

void main()
{   
    gl_FragData[0] = vec4(1.0,1.0,1.0,1.0);
}

UPDATE 2

My uniforms are created at load time. I have a class that looks for uniforms in a shader, and stores them to a map: the key is the uniform name, and the second value contains a GLuint handle. I use glGetUniformLocation() after creating a shader program, attaching shaders and linking it. I also do it after loading textures, so samplers will have a valid values.

Here is an example of loading my shader:

this->m_ShaderList[shaderName] = new CShaderProg(shaderName, true); // This just calls to glCreateProgram() and returns the handle
this->m_ShaderList[shaderName]->AttachShader(ShaderManager::CShader(*this->m_ptrMan->GetShaderSource(sVert), true));
this->m_ShaderList[shaderName]->AttachShader(ShaderManager::CShader(*this->m_ptrMan->GetShaderSource(sFrag), true));
this->m_ShaderList[shaderName]->LinkProgram();

...

// Then I check through each shader attached, adding uniform locations, if they don't exist
// If not found, add to list
if(it == this->m_UniformList.end()) {
    GLint tmpint = 1; // this is just a dummy value. Initialising to -1 or 0 makes glGetUniformLocation() return -1
    this->m_UniformList[VSdata[i+2]] = glGetUniformLocation(tmpint, VSdata[i+2].c_str());
}

I changed the code in the shaders to use layout(location = n) as I don't do any attribute binding (I never have). I use VAO/VBO for my geometry and pass in the values to my shaders using glEnableVertexAttribArray() and glDrawElements().

Something to note, using the G-Buffer shader on my second FBO results in geometry being rendered.

Sorry for such a lengthy post, but I've been having this problem for a few weeks now, and I just want to get to the bottom of why FBOs work for everyone else but me. The only other time I have found someone with this problem is here, but it was never answered.

\$\endgroup\$
  • \$\begingroup\$ +1: Much better than your last question, this one actually contains a lot of useful information :) \$\endgroup\$ – Andon M. Coleman Aug 30 '13 at 23:30
  • \$\begingroup\$ Are you aware that gl_FragData [n] is invalid in an OpenGL 3.3 core profile GLSL fragment shader? You should be using out vec4 ... and glBindFragDataLocation (...). I also think that any compliant GLSL compiler should be yelling at you for trying to do this :) \$\endgroup\$ – Andon M. Coleman Aug 30 '13 at 23:34
  • \$\begingroup\$ @AndonM.Coleman Yes I am aware of it. The shader works fine just for now but it is something I'm going to rectify later. I also have used many other shaders before with deprecated code that work, its just when trying to render to another custom FBO with a different shader, that's when problems arise. \$\endgroup\$ – Soapy Aug 30 '13 at 23:40
  • \$\begingroup\$ @AndonM.Coleman I've added code to the question. Forgive me for posting the actual code to the uniform location and usage, as it is wrapped up in classes. I felt no need to post it as all of my uniform handles have valid locations at runtime. \$\endgroup\$ – Soapy Aug 31 '13 at 0:09
  • 1
    \$\begingroup\$ Your fragment shader for the G-Buffer is also invalid, you have to match interpolation qualifiers. I am honestly surprised that your GLSL shader is not giving you 10-20 warnings per-shader. \$\endgroup\$ – Andon M. Coleman Aug 31 '13 at 0:47
3
\$\begingroup\$

Turns out my problem was with the uniform locations.

I wasn't querying the uniform location when using a different shader and I was only querying an abritray value (value of GLuint(1)), not an actual program, which is why my first shader created (which I used on my first FBO) worked and my second shader created(which I use on my second FBO) didn't work.

Now I know that uniforms are only valid across one shader, not multiple ones.

Thanks @Andon M. Coleman!

\$\endgroup\$
  • 4
    \$\begingroup\$ I would add one thing to that... the term shader technically refers to a single stage (e.g. vertex, geometry, tessellation (hull (D3D)/control (GL),domain (D3D)/evaluation (GL)), pixel (D3D)/fragment (GL)). A program is a collection of linked shader stages, it is more accurate to think of uniforms as a program-state than shader since their locations are only determined after you link all shader stages together. If two shader stages use the same name uniform in the same program, the location is identical. \$\endgroup\$ – Andon M. Coleman Sep 1 '13 at 1:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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