The Problem
I work on the open source game torcs (http://torcs.sourceforge.net/). The game's graphic pipeline is still using the fixed function pipeline (FFP) of OpenGL 1.3.
I try to render the game scenes to textures in a FBO (Framebuffer Object) in order to do some post-processing on the rendered textures. I use OpenGL 3.3. on my machine.
Currently I have set up the FBO with attached textures at GL_COLOR_ATTACHMENT0&1
(2 in order to have two consecutive frames readable in the shader) and an attached renderbuffer at GL_DEPTH_ATTACHMENT
.
After binding the FBO the game rendering function is executed. When I afterwards unbind the FBO and for validation write back the texture via a shader program to the window buffer the scene is incomplete. To be more specific, only the outline of the car is rendered, so are skidmarks of the tires and some smoke. This shows that something is rendered to the texture of the FBO, but not everything. Among others no textures (for trees, houses, grass etc.) are rendered to the texture in the FBO. This suggests that my texture set up is incorrect, but unfortunately my knowledge of OpenGL is limited, which is why I hope for your help.
One other thing worth noting is, that if I leave out the line glActiveTexture(GL_TEXTURE0);
before the drawing happens then one texture will be displayed (i.e. will be written to the FBO and written back to the window system framebuffer instead of the car outline.
The Code
The following code shows the initialization of the FBO (from https://en.wikibooks.org/wiki/OpenGL_Programming/Post-Processing):
int screen_width = 640;
int screen_height = 480;
/* Texture A*/
glGenTextures(1, &fbo_texture);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
/* Texture B*/
//glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &fbo_texture_a);
glBindTexture(GL_TEXTURE_2D, fbo_texture_a);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
/* Depth buffer */
glGenRenderbuffers(1, &rbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width, screen_height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
/* Framebuffer to link everything together */
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fbo_texture_a, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "glCheckFramebufferStatus: error 0x%x", status);
return 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/* Compile and link shaders */
...
The following code shows where the drawing happens:
Edit: if use_fbo=false
then everything will be rendered to screen directly as before. The only changes I made are within the brackets.
if (use_fbo)
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0,0,grWinw, grWinh);
if (fbo_a) // drawing to fbo_texture_a
{
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glActiveTexture(GL_TEXTURE0+11);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture_a);
}
else
{
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glActiveTexture(GL_TEXTURE0+12);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
}
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
}
glClearColor(0.7f, 0.1f, 0.1f, 1.0f); //clear with red to see what is drawn to the fbo
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
grScreens[0]->update(s, grFps);//THIS IS WHERE THE DRAWING HAPPENS unchanged from original drawing in TORCS
if (use_fbo)
{
glPopAttrib();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_TEXTURE_2D);
glDrawBuffer(GL_BACK);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(program_postproc);
if (fbo_a) // drawn to fbo_texture_a
{
glUniform1i(uniform_fbo_texture, 11);
glUniform1i(uniform_fbo_texture_a, 12);
fbo_a=!fbo_a;
}
else
{
glUniform1i(uniform_fbo_texture, 12);
glUniform1i(uniform_fbo_texture_a, 11);
fbo_a=!fbo_a;
}
glEnableVertexAttribArray(attribute_v_coord_postproc);
glBindBuffer(GL_ARRAY_BUFFER, vbo_fbo_vertices);
glVertexAttribPointer(
attribute_v_coord_postproc, 2, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(attribute_v_coord_postproc);
glUseProgram(0);
}
I hope I provided enough information for you to help me with this. Any advice is appreciated.
EDIT: I checked my shader code and FBO implementation again (simplified it to just one color attachment etc. with a simplified drawing) and it all worked. I think the trouble is the mix of fixed function pipeline for drawing and my implementation of the FBO...
EDIT: here are two images of what happens with use_fbo=true vs. false: (Note: the red color is the clear color after the FBO is bound, to see what gets rendered to the fbo: nothing apart from the shadow and skid marks)
I also tried to visualize the depth buffer (changed the implementation to a texture attachment for depth) and even though I linearized, there was no information. I suppose the depth is not correctly written to the FBO either.