FrameBufferObjects in OpenGL

FrameBufferObjects are basically off-screen frame buffers, similar to the regular frame buffer you are normally rendering to. Using FBOs in OpenGL you can do some nice stuff like post-processing or rendering to a texture. There's a difference between:
  • FrameBufferObjects: FBOs can be bound to / used as a texture, but performance may be lower.
and
Here's a example of how to set up an intermediate frame buffer, complete with a depth buffer:
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

struct FBOInfo {
    GLuint id;
    GLuint color;
    GLuint depth;
};

GLuint createTexture2D(const int w, const int h, GLint internalFormat, GLenum format, GLenum type)
{
    GLuint textureId;
    glGenTextures(1, &textureId);
    glBindTexture(GL_TEXTURE_2D, textureId);
    //NOTE: You should use GL_NEAREST here. Other values can cause problems
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    if (GL_DEPTH_COMPONENT == format) {
        //sample like regular texture, value is in all channels
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
        glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
    }
    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, type, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
    return textureId;
}

bool createFBO(FBOInfo & fboInfo)
{
    bool result = false;
    //generate textures for FBO usage. You could use other formats here, e.g. GL_RGBA8 for color
    fboInfo.color = createTexture2D(SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGBA16F, GL_RGBA, GL_FLOAT);
    fboInfo.depth = createTexture2D(SCREEN_WIDTH, SCREEN_HEIGHT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_FLOAT);
    //generate and bind FBO
    glGenFramebuffers(1, &fboInfo.id);
    glBindFramebuffer(GL_FRAMEBUFFER, fboInfo.id);
    //bind color and depth texture to FBO you could also use glFramebufferTexture2D with GL_TEXTURE_2D
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboInfo.color, 0);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, fboInfo.depth, 0);
    //check if FBO was created ok
    if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
        printf("FBO %d set up successfully. Yay!\n", fboInfo.id);
        result = true;
    }
    else {
        printf("FBO %d NOT set up properly!\n", fboInfo.id);
    }
    //unbind FBO for now
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    return result;
}
When you want to use the FBO for rendering do:
//setup framebuffer object
FBOInfo fboInfo;
createFBO(fboInfo);
Then in your rendering loop do:
//REMEMBER to enable depth buffer. Otherwise nothing is written to it!
glEnable(GL_DEPTH_TEST);
//bind the FBO as the current frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, fboInfo.id);
//then render your stuff
glRectf(-1,-1,1,1);
//now bind the regular frame buffer again
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Now you have the color and depth buffer available as a texture and can do nice things with it. See here on how to use those textures in shaders.

Comments