OpenGL: only one FBO at a time works

367 views Asked by At

I'm trying to render to a texture, then copy that texture and run it through post processing, then combine the filtered image with the original. I've got it so I can render to a a texture, then process it and display it, but I can only process it once. I'm really not sure what's going wrong.

Here is my FBO setup code:

for (int i = 0; i < 3; i++) {
    glGenFramebuffers(1, &postfboId[i]);
    glGenTextures(1, &postTextureId[i]);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, postTextureId[i]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    //float color[4] = {0.0, 0.0, 0.0, 1.0};
    //glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, screenSize.x, screenSize.y, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

    // create a framebuffer object
    glBindFramebuffer(GL_FRAMEBUFFER, postfboId[i]);


    glGenRenderbuffers(1, &depthrenderbuffer[i]);
    glBindRenderbuffer(GL_RENDERBUFFER, depthrenderbuffer[i]);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenSize.x, screenSize.y);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthrenderbuffer[i]);


    // attach the texture to FBO depth attachment point
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, postTextureId[i], 0);

    }
    GLenum DrawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
    glDrawBuffers(1, DrawBuffers);
    // check FBO status
    FBOstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if(FBOstatus != GL_FRAMEBUFFER_COMPLETE)
        printf("hey man, you might want to sit down a minute, i didn't want to have to say this to you, but the FBO failed.\n");

I thought maybe I need glDrawBuffers to make 3 instead of 1, but this just causes the FBO to be incomplete. Here is my render code:

glBindFramebuffer(GL_FRAMEBUFFER,postfboId[0]);
sf::Vector2u size = screenSize;
changeSize(size.x, size.y);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 
//clear viewport
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glUseProgram(prog);

glPushMatrix();

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
setLookat();
glCullFace(GL_BACK);
setLights();
drawObjs();

glPopMatrix();

//first round post process
glClearColor(0, 0, 0, 1);
glUseProgram(postProg);

glBindFramebuffer(GL_FRAMEBUFFER,postfboId[1]);
glUniform1i(postProcessMode, 1);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPushMatrix();
glLoadIdentity();
glOrtho(0,screenSize.x,0,screenSize.y,-1,20);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPushMatrix();
glLoadIdentity();
glColor4f(1,1,1,1);
glUniform1i(texUniform3, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,postTextureId[0]);
glEnable(GL_TEXTURE_2D);
glTranslated(0,0,-19.5);
glBegin(GL_QUADS);
glTexCoord2d(0,0);glVertex3f(0,0,0);
glTexCoord2d(1,0);glVertex3f(screenSize.x,0,0);
glTexCoord2d(1,1);glVertex3f(screenSize.x,screenSize.y,0);
glTexCoord2d(0,1);glVertex3f(0,screenSize.y,0);
glEnd();


// round 2 post
glUniform1i(postProcessMode, 2);
glBindFramebuffer(GL_FRAMEBUFFER,0);

glUniform1i(texUniform3, 3);
glActiveTexture(GL_TEXTURE3);
// bind postTextureId[0] to draw real screen.
glBindTexture(GL_TEXTURE_2D,postTextureId[1]);
glEnable(GL_TEXTURE_2D);
glTranslated(0,0,0.5);
glBegin(GL_QUADS);
glTexCoord2d(0,0);glVertex3f(0,0,0);
glTexCoord2d(1,0);glVertex3f(screenSize.x,0,0);
glTexCoord2d(1,1);glVertex3f(screenSize.x,screenSize.y,0);
glTexCoord2d(0,1);glVertex3f(0,screenSize.y,0);
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();

For whatever reason, drawing an FBOs texture to another FBO results in nonsense, but drawing that FBO texture to the screen is fine. Also, all 3 FBOs work, just not at the same time, which is odd since I have another FBO with just a depth buffer for shadowmapping which displays correctly.

1

There are 1 answers

1
Reto Koradi On BEST ANSWER

One immediately apparent problem is that you're missing glClear() calls for all but the first render target. You call it once after binding fbo 0:

glBindFramebuffer(GL_FRAMEBUFFER,postfboId[0]);
...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

But you'll also need to clear after binding fbo 1:

glBindFramebuffer(GL_FRAMEBUFFER,postfboId[1]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

and after binding the default framebuffer:

glBindFramebuffer(GL_FRAMEBUFFER,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

Some of your glPushMatrix() and glPopMatrix() calls also look somewhat suspicious. But it's hard to tell if they are incorrect without seeing the whole code. You may want to double check that they all balance, and that you're in the right matrix mode when calling them. For example in this sequence:

glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPushMatrix();
glLoadIdentity();

the glPopMatrix() and glPushMatrix() calls are redundant. If anything, they could be harmful because there would be an error if you did not previously call glPushMatrix(). Otherwise, it will first copy the previous matrix to the top entry, but then immediately overwrite it with the identity matrix. Which is the same as just calling glLoadIdentity() by itself.