Read me About Demoscene? Links Contact

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:

  1. Draw scene
  2. Copy scene for processing
  3. Perform post-processing
  4. 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