Rendering to Multiple Textures Separately

Hi. I’m trying to render to multiple FBOs with texture storage. Ultimately, the rendered content will change for each, so multiple render targets is not an option. However, with N FBOs, only the last contains the correct color data. Every prior texture contains the default framebuffer color data in a viewport whose size is the same as the default framebuffer’s. What would cause this?

Here’s the FBO initialization:


  glGenFramebuffers(3, fids);
  glGenTextures(3, tids);

  for (int i = 0; i < 3; ++i) {
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fids[i]);
    glActiveTexture(GL_TEXTURE0 + i);
    glBindTexture(GL_TEXTURE_2D, tids[i]);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_FLOAT, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tids[i], 0);
  }

The framebuffers are framebuffer complete. Here’s the drawing routine:


  for (int i = 0; i < 3; i++) {
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fids[i]);
    glViewport(0, 0, 1024, 1024);
    glClear(GL_COLOR_BUFFER_BIT);
    // render a bunch of lines in white
  }
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  // render a bunch of lines in red

And that leads to this result:

Only the last FBO’s texture is correct. The others contain the default FBO content, sized at 512x512.

Your wisdom is appreciated.

  • Chris

Do you draw the same lines each times (for the 3 FBO and for the default buffer) ? If not, all your textures have the same lines, only the color changes.

Can you try to call to glTexture2D out of the FBO ? Plus, I’m not sure ActiveTexture is usefull inside FBO.

Yes, I intentionally draw the same lines for now, just using a different color.

  • Chris

Try to draw different things to ensure what is drawn inside your different FBO.

For me, everything else is OK (but the texture creation I do outside from FBO).

It really is the default framebuffer content in textures 1 to N-1. If I don’t draw anything to the default framebuffer, I get the clear color in the textures.

  • Chris

The code should work well. Probably the error is elsewhere.

Few tips:

  • There is no need use more texture units. Just call glActiveTexture(GL_TEXTURE0); once.
  • It does not hurt to call glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); and glBindTexture(GL_TEXTURE_2D, 0); after your init code. It helps avoiding unintentional modification.
  • Try calling glCheckFramebufferStatus after glFramebufferTexture2D(). It should return GL_FRAMEBUFFER_COMPLETE.

What’s odd is that this problem first manifested itself in the project that a student of mine was working on. He has a decent ATI card and runs under Windows. He sent me his initialization and draw methods only.

I took his code and inserted it into a completely separate renderer on my Linux laptop with an NVIDIA GeForce Go 7300 and saw the exact same problem that he did.

Different manufacturers, drivers, renderers, and developers, same bug. It seems like we’re violating the specification somewhere.

Binding the default FBO and unbinding the texture after setup has no impact. I do check for framebuffer completeness.

  • Chris

You use a specific texture unit when creating your FBO. Maybe you should do the same when rendering to the FBO ? Do you have any special reason to use glActiveTexture ?
At last you can try to not use any texture unit at all.

I don’t think you violate the specifications, maybe just some mismatches.

I think the problem was a mirage. When I actually apply the textures to geometry, they all look identical and just fine. It’s only when I inspect them in gDEBugger that they are wrong.

I’m going to offer them the following self-contained example that reproduces the problem:


#define GL_GLEXT_PROTOTYPES
#include <GL/glut.h>

/* ------------------------------------------------------------------------- */

GLuint fids[3];
GLuint tids[3];

/* ------------------------------------------------------------------------- */

void initialize() {
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  glGenFramebuffers(3, fids);
  glGenTextures(3, tids);

  for (int i = 0; i < 3; ++i) {
    glBindTexture(GL_TEXTURE_2D, tids[i]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fids[i]);
    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tids[i], 0);
  }
  
  glBindTexture(GL_TEXTURE_2D, 0);
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  glLineWidth(5.0f);
}

/* ------------------------------------------------------------------------- */

void display() {
  // Draw horizontal lines to textures
  for (int i = 0; i < 3; i++) {
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fids[i]);
    glViewport(0, 0, 1024, 1024);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_LINES);
    glVertex2f(-1.0f, 0.0f);
    glVertex2f(1.0f, 0.0f);
    glEnd();
  }

  glColor3f(1.0f, 0.0f, 0.0f);


  // Draw vertical line to default FBO
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
  glViewport(0, 0, 512, 512);
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_LINES);
  glVertex2f(0.0f, -1.0f);
  glVertex2f(0.0f, 1.0f);
  glEnd();

  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  glBindTexture(GL_TEXTURE_2D, tids[0]);
  glEnable(GL_TEXTURE_2D);
  glBegin(GL_QUADS);
  glTexCoord2f(0.0f, 0.0f);
  glVertex2f(0.5f, 0.5f);
  glTexCoord2f(1.0f, 0.0f);
  glVertex2f(1.0f, 0.5f);
  glTexCoord2f(1.0f, 1.0f);
  glVertex2f(1.0f, 1.0f);
  glTexCoord2f(0.0f, 1.0f);
  glVertex2f(0.5f, 1.0f);
  glEnd();
  glDisable(GL_TEXTURE_2D);

  glutSwapBuffers();
}

/* ------------------------------------------------------------------------- */

int main(int argc, char **argv) {
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
  glutInitWindowSize(512, 512);
  glutInit(&argc, argv);
  glutCreateWindow("Boo, FBOs!");
  initialize();
  glutDisplayFunc(display);
  glutIdleFunc(display);
  glutMainLoop();

  return 0;
}

/* ------------------------------------------------------------------------- */

  • Chris