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.
- RenderbufferObjects: Those can not be used as textures, but rendering to them may be faster. When you want to retrieve content of a RenderbufferObject or want to use it as a texture you’ll have to use pixel transfer operations like glReadPixels first.
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.