Easy Frame Buffer Object class
So, I’ve been fiddling a lot with frame buffer objects lately. And before you get to it - Yes, I know I’m several years behind :-)
For those of you who don’t know what Frame Buffer Objects are - they are frame buffers stored in your video memory which can be used as any other texture in OpenGL. It replaces the insanely slow glCopyPixels which copy an area of the current context into conventional memory for processing.
Why is this cool? Well, let’s say you want to do glow, motion blur, radial blur or some other post processing - you’ll have to follow this recipe:
- Draw scene
- Copy scene for processing
- Perform post-processing
- Blit post-processing
Using glCopyPixels you’ll have to transfer data from video memory to conventional memory in step 2 and vice versa in step 4.
With frame buffer objects the data transfer is happening internally in the video memory, i.e. step 2 transfers data from the render context into the frame buffer object and vice versa in step 4.
…. and here’s the code:
class FBO
{
private:
HANDLE render_texture_handle;
unsigned int render_texture;
unsigned int render_texture_x, render_texture_y;
unsigned int render_fbo, render_rbo;
public:
unsigned int Texture()
{
return render_texture;
}
void Enable()
{
CViewport vp(render_texture_x, render_texture_y);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo);
}
void Disable()
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
FBO()
{
render_texture_x = COpenGL::WIDTH;
render_texture_y = COpenGL::HEIGHT;
// allocate texture
glGenTextures(1, &render_texture);
glBindTexture(GL_TEXTURE_2D, render_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, render_texture_x, render_texture_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// allocate framebuffer
glGenFramebuffersEXT(1, &render_fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_texture, 0);
// bind framebuffer and renderbuffer
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_rbo);
// check status
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
throw "FBO not ready";
}
// clear texture
Enable();
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
Disable();
}
};
… and here is an example application in pseudo-c++:
void Render()
{
FragmentShader postproc;
FBO fbo;
Scene scene;
while (true)
{
// turn fbo on
fbo.Enable();
// render awesome scene
scene.Render();
// disable fbo
fbo.Disable();
// enable fragment shader for post processing
postproc.Enable();
// bind the fbo texture handle
glBindTexture2D(GL_TEXTURE_2D, fbo.Texture());
// draw quad that fills the whole screen
glRecti(...);
// disable fragment shader
postproc.Disable();
}
}
You can find my fragment shader class elsewhere on this blog
