FBO: basics and usage

dear embers,
I am new to Cinder and Graphics in general, and I am struggling with the theory / technique behind the FBO samples.
I started with an app that rendered directly to the screen. Now I managed to render stuff to an FBO first then to the screen and I am hoping I can add some post processing. Things seem to have a slowed a bit and it seems the push / pop matrices calls are the culprit. I am a bit confused with the “Scoped” calls (ScopedFramebuffer, ScopedViewport etc…) and how things are rendered inside a block { }.
Any pointers to any literature would be greatly appreciated.
thank you

Hi,

the gl::Scoped* calls allow you to temporarily store the current value, change it and automatically restore it as soon as the scoped variable is destroyed (goes out of scope):

// Set the current drawing color to white.
gl::color( 1, 1, 1); 
// Enter new scope.
{
    // Store current drawing color, then set it to red.
    gl::ScopedColor scpColor( 1, 0, 0 );

    // Draw something...
    gl::drawSolidCircle( getWindowCenter(), 40.0f );

    // The "scpColor" variable will now go out of scope and will be destroyed.
    // The current drawing color will be reset to white.
}

// Draw something...
gl::drawSolidCircle( getWindowCenter(), 20.0f );

The result should be a red circle with a smaller white circle on top of it.

Scoped variables follow a programming idiom called RAII and you are encouraged to use it throughout your code. This way, you can be sure values and states are always restored to their original value when exiting a scope, even in the event of an exception or error (if handled).

This is especially important for matrices, most notably when rendering nested transformations, like a robot arm. Assuming the arm consists of a cylinder for the arm (from shoulder to elbow), a cylinder for the forearm (from elbow to wrist) and a box for the hand. The hand can move independently of the forearm, but if the forearm moves the hand should follow. In computer terms: each of the three parts has a local matrix and they should be applied as follows:

void drawArm()
{
    gl::multModelMatrix( mArmMatrix );
    mArmMesh->draw();

    gl::multModelMatrix( mForearmMatrix ); // combines arm & forearm
    mForearm->draw(); 

    gl::multModelMatrix( mHandMatrix ); // combines arm, forearm & hand
    mHand->draw(); 
}

But now we are done drawing and want to draw something else. We need to reset the model matrix to the value it had before we drew the arm. We could do this:

gl::pushModelMatrix(); // temporarly store the current matrix on the "model matrix stack"
drawArm();
gl::popModelMatrix(); // restore the model matrix to what it was before

, but this is safer (because you don’t have to remember to call popModelMatrix and is exception safe):

{
    gl::ScopedModelMatrix scpModel;
    drawArm();
}

Of course, it’s even better to create a gl::ScopedModelMatrix at the beginning of drawArm()!

-Paul

P.S.: a bit more info on how to properly set viewports and so on, can be found on the old forum. Note that the code was written for Cinder v0.8.6, which did not have the gl::Scoped* classes yet.

Paul,
thank you so much for taking the time for explaining scopes!! This is very helpful
Now I have seen examples that render FBOs on update and other on draw? When I tried rendering an FBO on update, I got a garbled image. Is there a fundamental difference between the 2?

Hi,

technically there should not be much difference. Both update and draw are called (multiple times) after setup (once), so OpenGL has been initialized and creating and rendering to an Fbo should just work. The frequency with which update and draw are called, however, is different. The update method is called once per frame, which usually is 60 times per second. The draw method is called once per frame per window and is also called when you resize the window. If you’re not sure where to draw to your Fbo, do it in draw.

If rendering to an Fbo fails, check to see if it has been initialized/created properly. Also check if your matrices are set correctly (especially the projection matrix) and if your viewport has been adjusted for the Fbo's size. And don’t forget to call gl::clear() after binding the Fbo :). Use gl::ScopedFrameBuffer to bind and automatically unbind the Fbo. If you’re using transparency, make sure to also clear the alpha channel with gl::clear( ColorA( 0, 0, 0, 0 ) );.

Let me know if you still have problems.

-Paul

awesome! i got it working on draw and I am not seeing a framerate drop.
thank you