PDA

View Full Version : Rendering to Multiple Textures Separately



kaerimasu
12-13-2010, 07:27 PM
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:
http://www.cs.iastate.edu/~cjohnson/forothers/shots.png

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

Your wisdom is appreciated.

- Chris

_arts_
12-14-2010, 04:17 AM
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.

kaerimasu
12-14-2010, 04:51 AM
Yes, I intentionally draw the same lines for now, just using a different color.

- Chris

_arts_
12-14-2010, 09:50 AM
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).

kaerimasu
12-14-2010, 12:24 PM
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

mfort
12-14-2010, 12:51 PM
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.

kaerimasu
12-14-2010, 10:19 PM
The code should work well. Probably the error is elsewhere.


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.



Few tips:
- 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.

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

- Chris

_arts_
12-15-2010, 03:29 AM
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.

kaerimasu
12-16-2010, 08:00 AM
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(&amp;argc, argv);
glutCreateWindow("Boo, FBOs!");
initialize();
glutDisplayFunc(display);
glutIdleFunc(display);
glutMainLoop();

return 0;
}

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


- Chris