# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

# Framebuffer Objects Tutorial

This tutorial shows how to use framebuffer objects to perform offscreen rendering.

Visualization Library uses the following classes to implement framebuffer objects and framebuffer attachments:

- vl::FramebufferObject
- vl::FBORenderbufferAttachment
- vl::FBOColorBufferAttachment
- vl::FBODepthBufferAttachment
- vl::FBODepthStencilBufferAttachment
- vl::FBOStencilBufferAttachment
- vl::FBOTexture1DAttachment
- vl::FBOTexture2DAttachment
- vl::FBOTexture3DAttachment
- vl::FBOTextureAttachment
- vl::FBOTextureLayerAttachment
- See also the `ARB_framebuffer_object` specifications http://www.opengl.org/registry/specs/ARB/framebuffer_object.txt

In this tutorial a scene with a few rotating toruses is rendered to a texture. Such texture is then applied to a cube and a plane in a second rendering.

[From `App_Framebuffer_Object.cpp`]

    class App_Framebuffer_Object: public BaseDemo
    {
      static const int mFBO_Size = 1024;

    public:
      App_Framebuffer_Object(int test): mTestNum(test) {}

      /*
      This example demonstates the use of the render-to-texture (RTT) technique using framebuffer objects.
      */
      void initTest_FBO_Render_To_Texture()
      {
        // Setup dual rendering

        vl::ref<vl::RenderingTree> render_tree = new vl::RenderingTree;
        setRendering(render_tree.get());
        mMainRendering = new vl::Rendering;
        mRTT_Rendering = new vl::Rendering;
        render_tree->subRenderings()->push_back(mRTT_Rendering.get());
        render_tree->subRenderings()->push_back(mMainRendering.get());
        mMainRendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);
        mRTT_Rendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);

        // RTT rendering

        mRTT_Rendering->camera()->viewport()->setClearColor( vl::crimson );
        mRTT_Rendering->camera()->viewport()->set(0, 0, mFBO_Size, mFBO_Size);
        mRTT_Rendering->camera()->setProjectionPerspective();
        vl::mat4 m = vl::mat4::getLookAt(vl::vec3(0,0,10.5f), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mRTT_Rendering->camera()->setViewMatrix(m);

        /* use a framebuffer object as render target */
        vl::ref<vl::FramebufferObject> framebuffer_object = openglContext()->createFramebufferObject(mFBO_Size, mFBO_Size);
        mRTT_Rendering->renderer()->setFramebuffer( framebuffer_object.get() );

        /* bind a depth buffer */
        vl::ref<vl::FBODepthBufferAttachment> fbo_depth_attachm = new vl::FBODepthBufferAttachment(vl::DBF_DEPTH_COMPONENT16);
        framebuffer_object->addDepthAttachment( fbo_depth_attachm.get() );

        /* use texture as color buffer */
        vl::ref<vl::Texture> texture = new vl::Texture(mFBO_Size, mFBO_Size, vl::TF_RGBA);
        vl::ref<vl::FBOTexture2DAttachment> fbo_tex_attachm = new vl::FBOTexture2DAttachment(texture.get(), 0, vl::T2DT_TEXTURE_2D);
        framebuffer_object->addTextureAttachment( vl::AP_COLOR_ATTACHMENT0, fbo_tex_attachm.get() );
        mRTT_Rendering->renderer()->framebuffer()->setDrawBuffer( vl::RDB_COLOR_ATTACHMENT0 );

        // Main rendering

        /* setup camera */
        mMainRendering->camera()->viewport()->setClearColor( vl::midnightblue );
        mMainRendering->camera()->viewport()->set(0, 0, openglContext()->framebuffer()->width(), openglContext()->framebuffer()->height());
        m = vl::mat4::getLookAt(vl::vec3(0,15,25), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mMainRendering->camera()->setViewMatrix(m);

        /* use the opengl window as render target */
        mMainRendering->renderer()->setFramebuffer( openglContext()->framebuffer() );

        /* populate the scene */
        addRings(NULL);
        addCube(texture.get(), NULL);
      }

      /*
      This example demonstates the use of the multiple-render-target tecnique to render on two textures simultaneously.
      */
      void initTest_FBO_Render_To_Texture_MRT()
      {
        if (!vl::Has_GLSL)
        {
          vl::Log::error("This test requires GLSL!\n");
          vl::Time::sleep(2000);
          exit(1);
        }
        // Setup dual rendering

        vl::ref<vl::RenderingTree> render_tree = new vl::RenderingTree;
        setRendering(render_tree.get());
        mMainRendering = new vl::Rendering;
        mRTT_Rendering = new vl::Rendering;
        render_tree->subRenderings()->push_back(mRTT_Rendering.get());
        render_tree->subRenderings()->push_back(mMainRendering.get());
        mMainRendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);
        mRTT_Rendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);

        // RTT rendering

        mRTT_Rendering->camera()->viewport()->setClearColor( vl::crimson );
        mRTT_Rendering->camera()->viewport()->set(0, 0, mFBO_Size, mFBO_Size);
        mRTT_Rendering->camera()->setProjectionPerspective();
        vl::mat4 m = vl::mat4::getLookAt(vl::vec3(0,0,10.5f), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mRTT_Rendering->camera()->setViewMatrix(m);

        /* use a framebuffer object as render target */
        vl::ref<vl::FramebufferObject> framebuffer_object = openglContext()->createFramebufferObject(mFBO_Size, mFBO_Size);
        mRTT_Rendering->renderer()->setFramebuffer( framebuffer_object.get() );

        /* bind a depth buffer */
        vl::ref<vl::FBODepthBufferAttachment> fbo_depth_attachm = new vl::FBODepthBufferAttachment(vl::DBF_DEPTH_COMPONENT16);
        framebuffer_object->addDepthAttachment( fbo_depth_attachm.get() );

        /* use a per-pixel-light GLSL shader which renders on two color attachments at the same time */
        vl::ref<vl::GLSLProgram> glsl = new vl::GLSLProgram;
        glsl->attachShader( new vl::GLSLVertexShader("/glsl/perpixellight.vs") );
        if (vl::Has_GL_EXT_gpu_shader4||vl::Has_GL_Version_3_0||vl::Has_GL_Version_4_0)
        {
          vl::Log::notify("using glBindFragDataLocation()\n");
          // see fragment shader sources for the details
          glsl->attachShader( new vl::GLSLFragmentShader("/glsl/perpixellight_cartoon_mrt2.fs") );
          glsl->bindFragDataLocation(0, "FragDataOutputA"); // out varying variable writing on color attachment #0
          glsl->bindFragDataLocation(1, "FragDataOutputB"); // out varying variable writing on color attachment #1
        }
        else
        {
          vl::Log::notify("glBindFragDataLocation() not supported.\n");
          // see fragment shader sources for the details
          glsl->attachShader( new vl::GLSLFragmentShader("/glsl/perpixellight_cartoon_mrt.fs") );
        }

        /* use two textures as color attachment #0 and #1 */
        vl::ref<vl::Texture> texture1 = new vl::Texture(mFBO_Size, mFBO_Size, vl::TF_RGBA);
        vl::ref<vl::Texture> texture2 = new vl::Texture(mFBO_Size, mFBO_Size, vl::TF_RGBA);
        vl::ref<vl::FBOTexture2DAttachment> fbo_tex_attachm1 = new vl::FBOTexture2DAttachment(texture1.get(), 0, vl::T2DT_TEXTURE_2D);
        vl::ref<vl::FBOTexture2DAttachment> fbo_tex_attachm2 = new vl::FBOTexture2DAttachment(texture2.get(), 0, vl::T2DT_TEXTURE_2D);
        framebuffer_object->addTextureAttachment( vl::AP_COLOR_ATTACHMENT0, fbo_tex_attachm1.get() );
        framebuffer_object->addTextureAttachment( vl::AP_COLOR_ATTACHMENT1, fbo_tex_attachm2.get() );

        /* draw on colorbuffers #0 and #1 */
        mRTT_Rendering->renderer()->framebuffer()->setDrawBuffers(vl::RDB_COLOR_ATTACHMENT0, vl::RDB_COLOR_ATTACHMENT1);

        /* screen shot grabbing on color attachment #0 */
        vl::ref<vl::ReadPixels> read_pixels_0 = new vl::ReadPixels;
        read_pixels_0->setup( 0, 0, mFBO_Size, mFBO_Size, vl::RDB_COLOR_ATTACHMENT0, false );
        mRTT_Rendering->onFinishedCallbacks()->push_back(read_pixels_0.get());
        read_pixels_0->setRemoveAfterCall(true);
        read_pixels_0->setSavePath("MRT-COLOR_ATTACHMENT0.tif");

        /* screen shot grabbing on color attachment #1 */
        vl::ref<vl::ReadPixels> read_pixels_1 = new vl::ReadPixels;
        read_pixels_1->setup( 0, 0, mFBO_Size, mFBO_Size, vl::RDB_COLOR_ATTACHMENT1, false );
        mRTT_Rendering->onFinishedCallbacks()->push_back(read_pixels_1.get());
        read_pixels_1->setRemoveAfterCall(true);
        read_pixels_1->setSavePath("MRT-COLOR_ATTACHMENT1.tif");

        // Main rendering

        /* setup camera */
        mMainRendering->camera()->viewport()->setClearColor( vl::midnightblue );
        mMainRendering->camera()->viewport()->set(0, 0, openglContext()->framebuffer()->width(), openglContext()->framebuffer()->height());
        m = vl::mat4::getLookAt(vl::vec3(0,15,25), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mMainRendering->camera()->setViewMatrix(m);

        /* use the opengl window as render target */
        mMainRendering->renderer()->setFramebuffer( openglContext()->framebuffer() );

        /* populate the scene */
        addRings(glsl.get());
        addCube(texture1.get(), texture2.get() );
      }

      /*
      This example shows how to perform off-screen rendering on a color buffer.
      The content of the colorbuffer is then copied to a texture using CopyTexSubImage2D.
      */
      void initTest_FBO_Render_To_Color_Buffer_And_Copy_To_Texture()
      {
        // Setup dual rendering

        vl::ref<vl::RenderingTree> render_tree = new vl::RenderingTree;
        setRendering(render_tree.get());
        mMainRendering = new vl::Rendering;
        mRTT_Rendering = new vl::Rendering;
        render_tree->subRenderings()->push_back(mRTT_Rendering.get());
        render_tree->subRenderings()->push_back(mMainRendering.get());
        mMainRendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);
        mRTT_Rendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);

        // RTT rendering

        mRTT_Rendering->camera()->viewport()->setClearColor( vl::crimson );
        mRTT_Rendering->camera()->viewport()->set(0, 0, mFBO_Size, mFBO_Size);
        mRTT_Rendering->camera()->setProjectionPerspective();
        vl::mat4 m = vl::mat4::getLookAt(vl::vec3(0,0,10.5f), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mRTT_Rendering->camera()->setViewMatrix(m);

        /* use a framebuffer object as render target */
        vl::ref<vl::FramebufferObject> framebuffer_object = openglContext()->createFramebufferObject(mFBO_Size, mFBO_Size);
        mRTT_Rendering->renderer()->setFramebuffer( framebuffer_object.get() );

        /* bind a depth buffer */
        vl::ref<vl::FBODepthBufferAttachment> fbo_depth_attachm = new vl::FBODepthBufferAttachment(vl::DBF_DEPTH_COMPONENT16);
        framebuffer_object->addDepthAttachment( fbo_depth_attachm.get() );

        /* bind a normal color buffer as color attachment #0 */
        vl::ref<vl::FBOColorBufferAttachment> fbo_col_buf_attachm = new vl::FBOColorBufferAttachment(vl::CBF_RGBA8);
        framebuffer_object->addColorAttachment( vl::AP_COLOR_ATTACHMENT0, fbo_col_buf_attachm.get() );
        mRTT_Rendering->renderer()->framebuffer()->setDrawBuffer(vl::RDB_COLOR_ATTACHMENT0);

        /* at the end of the rendering copy the color attachment pixels into the texture */
        vl::ref<vl::Texture> texture = new vl::Texture(mFBO_Size, mFBO_Size, vl::TF_RGBA, false); // note that mipmapping is off
        vl::ref<vl::CopyTexSubImage2D> copytex = new vl::CopyTexSubImage2D(0, 0,0, 0,0, mFBO_Size,mFBO_Size, texture.get(), vl::T2DT_TEXTURE_2D, vl::RDB_COLOR_ATTACHMENT0);
        mRTT_Rendering->onFinishedCallbacks()->push_back(copytex.get());

        // Main rendering

        /* setup camera */
        mMainRendering->camera()->viewport()->setClearColor( vl::midnightblue );
        mMainRendering->camera()->viewport()->set(0, 0, openglContext()->framebuffer()->width(), openglContext()->framebuffer()->height());
        m = vl::mat4::getLookAt(vl::vec3(0,15,25), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mMainRendering->camera()->setViewMatrix(m);

        /* use the opengl window as render target */
        mMainRendering->renderer()->setFramebuffer( openglContext()->framebuffer() );

        /* populate the scene */
        addRings(NULL);
        addCube(texture.get(), NULL);
      }

      /*
      This example shows how to perform off-screen rendering on a multisampled color buffer and then copy
      the content of such buffer to a non-multisampled texture using the vl:BlitFramebuffer callback object.
      */
      void initTest_FBO_Framebuffer_Blit_Multisample()
      {
        if (!(vl::Has_GL_EXT_framebuffer_multisample||vl::Has_GL_EXT_framebuffer_blit||vl::Has_GL_Version_3_0||vl::Has_GL_Version_4_0))
        {
          vl::Log::error("Framebuffer multisample blitting not supported.\n");
          vl::Time::sleep(2000);
          exit(1);
        }

        const int samples = 4;

        // Setup dual rendering

        vl::ref<vl::RenderingTree> render_tree = new vl::RenderingTree;
        setRendering(render_tree.get());
        mMainRendering = new vl::Rendering;
        mRTT_Rendering = new vl::Rendering;
        render_tree->subRenderings()->push_back(mRTT_Rendering.get());
        render_tree->subRenderings()->push_back(mMainRendering.get());
        mMainRendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);
        mRTT_Rendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);

        // RTT rendering

        mRTT_Rendering->camera()->viewport()->setClearColor( vl::crimson );
        mRTT_Rendering->camera()->viewport()->set(0, 0, mFBO_Size, mFBO_Size);
        mRTT_Rendering->camera()->setProjectionPerspective();
        vl::mat4 m = vl::mat4::getLookAt(vl::vec3(0,0,10.5f), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mRTT_Rendering->camera()->setViewMatrix(m);

        /* use a framebuffer object as render target */
        vl::ref<vl::FramebufferObject> framebuffer_object = openglContext()->createFramebufferObject(mFBO_Size, mFBO_Size);
        mRTT_Rendering->renderer()->setFramebuffer( framebuffer_object.get() );

        /* bind a multisampled depth buffer */
        vl::ref<vl::FBODepthBufferAttachment> fbo_depth_attachm = new vl::FBODepthBufferAttachment(vl::DBF_DEPTH_COMPONENT16);
        fbo_depth_attachm->setSamples(samples);
        framebuffer_object->addDepthAttachment( fbo_depth_attachm.get() );

        /* bind a multisampled color buffer */
        vl::ref<vl::FBOColorBufferAttachment> fbo_col_buf_attachm = new vl::FBOColorBufferAttachment(vl::CBF_RGBA);
        fbo_col_buf_attachm->setSamples(samples);
        framebuffer_object->addColorAttachment( vl::AP_COLOR_ATTACHMENT0, fbo_col_buf_attachm.get() );
        mRTT_Rendering->renderer()->framebuffer()->setDrawBuffer(vl::RDB_COLOR_ATTACHMENT0);

        /* create a new FBO with 'texture' as its color attachment */
        vl::ref<vl::FramebufferObject> fbo_rt_texture = openglContext()->createFramebufferObject(mFBO_Size, mFBO_Size);
        vl::ref<vl::Texture> texture = new vl::Texture(mFBO_Size, mFBO_Size, vl::TF_RGBA);
        vl::ref<vl::FBOTexture2DAttachment> fbo_tex_attachm = new vl::FBOTexture2DAttachment(texture.get(), 0, vl::T2DT_TEXTURE_2D);
        fbo_rt_texture->addTextureAttachment( vl::AP_COLOR_ATTACHMENT0, fbo_tex_attachm.get() );

        /* setup vl::BlitFramebuffer: blits the content of the multisampled color buffer into a non-multisampled texture */
        vl::ref<vl::BlitFramebuffer> blit_fbo = new vl::BlitFramebuffer;
        mRTT_Rendering->onFinishedCallbacks()->push_back(blit_fbo.get());
        blit_fbo->setLinearFilteringEnabled(false);
        blit_fbo->setBufferMask( vl::BB_COLOR_BUFFER_BIT );
        //the commented part does not work with multisampling enabled (samples > 0)
        //int center = mFBO_Size / 2;
        //int side   = mFBO_Size / 4;
        //blit_fbo->setSrcRect( center-side, center-side, center+side, center+side );
        blit_fbo->setSrcRect( 0, 0, mFBO_Size, mFBO_Size );
        blit_fbo->setDstRect( 0, 0, mFBO_Size, mFBO_Size );
        blit_fbo->setReadFramebuffer( framebuffer_object.get() );
        blit_fbo->setDrawFramebuffer( fbo_rt_texture.get() );

        // Main rendering

        /* setup camera */
        mMainRendering->camera()->viewport()->setClearColor( vl::midnightblue );
        mMainRendering->camera()->viewport()->set(0, 0, openglContext()->framebuffer()->width(), openglContext()->framebuffer()->height());
        m = vl::mat4::getLookAt(vl::vec3(0,15,25), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mMainRendering->camera()->setViewMatrix(m);

        /* use the opengl window as render target */
        mMainRendering->renderer()->setFramebuffer( openglContext()->framebuffer() );

        /* populate the scene */
        addRings(NULL);
        addCube(texture.get(), NULL);
      }

      /*
      This example shows how to perform off-screen rendering directly on a multisample texture.
      */
      void initTest_FBO_Multisample_Texture()
      {
        if (!(vl::Has_GL_ARB_texture_multisample||vl::Has_GL_Version_3_2||vl::Has_GL_Version_4_0))
        {
          vl::Log::error("Multisample texture not supported.\n");
          vl::Time::sleep(2000);
          exit(1);
        }

        const int samples = 4; // keep updated with tex_multisample.fs

        // Setup dual rendering

        vl::ref<vl::RenderingTree> render_tree = new vl::RenderingTree;
        setRendering(render_tree.get());
        mMainRendering = new vl::Rendering;
        mRTT_Rendering = new vl::Rendering;
        render_tree->subRenderings()->push_back(mRTT_Rendering.get());
        render_tree->subRenderings()->push_back(mMainRendering.get());
        mMainRendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);
        mRTT_Rendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);

        // RTT rendering

        mRTT_Rendering->camera()->viewport()->setClearColor( vl::crimson );
        mRTT_Rendering->camera()->viewport()->set(0, 0, mFBO_Size, mFBO_Size);
        mRTT_Rendering->camera()->setProjectionPerspective();
        vl::mat4 m = vl::mat4::getLookAt(vl::vec3(0,0,10.5f), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mRTT_Rendering->camera()->setViewMatrix(m);

        /* use a framebuffer object as render target */
        vl::ref<vl::FramebufferObject> framebuffer_object = openglContext()->createFramebufferObject(mFBO_Size, mFBO_Size);
        mRTT_Rendering->renderer()->setFramebuffer( framebuffer_object.get() );

        /* bind a multisampled depth buffer */
        vl::ref<vl::FBODepthBufferAttachment> fbo_depth_attachm = new vl::FBODepthBufferAttachment(vl::DBF_DEPTH_COMPONENT16);
        fbo_depth_attachm->setSamples(samples);
        framebuffer_object->addDepthAttachment( fbo_depth_attachm.get() );

        /* use multisample texture as color buffer */
        vl::ref<vl::Texture> texture = new vl::Texture;
        texture->prepareTexture2DMultisample(mFBO_Size, mFBO_Size, vl::TF_RGBA, samples, true);
        texture->createTexture();
        vl::ref<vl::FBOTexture2DAttachment> fbo_tex_attachm = new vl::FBOTexture2DAttachment(texture.get(), 0, vl::T2DT_TEXTURE_2D_MULTISAMPLE);
        framebuffer_object->addTextureAttachment( vl::AP_COLOR_ATTACHMENT0, fbo_tex_attachm.get() );
        mRTT_Rendering->renderer()->framebuffer()->setDrawBuffer( vl::RDB_COLOR_ATTACHMENT0 );

        // Main rendering

        /* setup camera */
        mMainRendering->camera()->viewport()->setClearColor( vl::midnightblue );
        mMainRendering->camera()->viewport()->set(0, 0, openglContext()->framebuffer()->width(), openglContext()->framebuffer()->height());
        m = vl::mat4::getLookAt(vl::vec3(0,15,25), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mMainRendering->camera()->setViewMatrix(m);

        /* use the opengl window as render target */
        mMainRendering->renderer()->setFramebuffer( openglContext()->framebuffer() );

        /* populate the scene */
        addRings(NULL);
        addCube(texture.get(), NULL); // here we use he /glsl/tex_multisample.fs to perform the texel fetch.
      }

      /*
      This example demonstrates how to perform render-to-texture without using framebuffer objects.
      First the scene with the ring is rendered normally on the screen. The pixels on the screen are then copied to
      a texture using the vl::CopyTexSubImage2D callback object. Finally the scene with the cube can be rendered
      using the previously generated texture.
      */
      void initTest_RTT_Legacy()
      {
        // Setup dual rendering

        vl::ref<vl::RenderingTree> render_tree = new vl::RenderingTree;
        setRendering(render_tree.get());
        mMainRendering = new vl::Rendering;
        mRTT_Rendering = new vl::Rendering;
        render_tree->subRenderings()->push_back(mRTT_Rendering.get());
        render_tree->subRenderings()->push_back(mMainRendering.get());
        mMainRendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);
        mRTT_Rendering->sceneManagers()->push_back(new vl::SceneManagerActorTree);

        /* both render to the screen */
        mMainRendering->renderer()->setFramebuffer( openglContext()->framebuffer() );
        mRTT_Rendering->renderer()->setFramebuffer( openglContext()->framebuffer() );

        // Render to texture rendering

        /* setup render-to-texture rendering: render to screen then copies to texture. */
        mRTT_Rendering->camera()->viewport()->setClearColor( vl::crimson );
        mRTT_Rendering->camera()->viewport()->set(0,0,512,512);
        mRTT_Rendering->camera()->setProjectionPerspective();
        vl::mat4 m = vl::mat4::getLookAt( vl::vec3(0,0,10.5f), vl::vec3(0,0,0), vl::vec3(0,1,0) );
        mRTT_Rendering->camera()->setViewMatrix( m );

        /* install copy to texture callback */
        vl::ref<vl::Texture> texture = new vl::Texture( 512, 512, vl::TF_RGBA, false );
        vl::ref<vl::CopyTexSubImage2D> copytex = new vl::CopyTexSubImage2D( 0, 0,0, 0,0, 512,512, texture.get() );
        mRTT_Rendering->onFinishedCallbacks()->push_back( copytex.get() );

        // Main rendering

        /* setup main rendering */
        mMainRendering->camera()->viewport()->setClearColor( vl::midnightblue );
        mMainRendering->camera()->viewport()->set(0,0,512,512);
        mMainRendering->camera()->setProjectionPerspective();
        m = vl::mat4::getLookAt(vl::vec3(0,15,25), vl::vec3(0,0,0), vl::vec3(0,1,0));
        mMainRendering->camera()->setViewMatrix( m );

        /* populate the scene */
        addCube(texture.get(), NULL);
        addRings(NULL);
      }

      void addCube(vl::Texture* texture1, vl::Texture* texture2)
      {
        vl::ref<vl::Light> light = new vl::Light;
        light->setAmbient( vl::fvec4( .1f, .1f, .1f, 1.0f) );
        light->setSpecular( vl::fvec4( .1f, .1f, .1f, 1.0f) );
        vl::ref<vl::Effect> effect1 = new vl::Effect;
        effect1->shader()->setRenderState( light.get(), 0 );
        effect1->shader()->gocLightModel()->setTwoSide(true);
        effect1->shader()->enable(vl::EN_LIGHTING);
        effect1->shader()->enable(vl::EN_DEPTH_TEST);
        effect1->shader()->gocTextureSampler(0)->setTexture( texture1 );
        effect1->shader()->gocTexEnv(0)->setMode(vl::TEM_MODULATE);
        // TD_TEXTURE_2D_MULTISAMPLE requires a special fragment shader
        if (texture1->dimension() == vl::TD_TEXTURE_2D_MULTISAMPLE)
        {
          effect1->shader()->gocGLSLProgram()->attachShader( new vl::GLSLFragmentShader("/glsl/tex_multisample.fs") );
          effect1->shader()->gocGLSLProgram()->gocUniform("ms_texture")->setUniformI(0);
        }

        // ground plane
        const vl::real size = 50;
        vl::ref<vl::Geometry> ground = vl::makeGrid( vl::vec3(0,0,0), size, size, 2, 2, true, vl::fvec2(0,0), vl::fvec2(1,1) );
        ground->computeNormals();
        mMainRendering->sceneManagers()->at(0)->as<vl::SceneManagerActorTree>()->tree()->addActor( ground.get(), effect1.get() );

        if (texture2)
        {
          // box #1
          vl::ref<vl::Geometry> box1 = vl::makeBox( vl::vec3(-7,5,0), 10,10,10);
          box1->computeNormals();
          mMainRendering->sceneManagers()->at(0)->as<vl::SceneManagerActorTree>()->tree()->addActor( box1.get(), effect1.get() );

          // box #2
          vl::ref<vl::Effect> effect2 = new vl::Effect;
          effect2->shader()->shallowCopyFrom(*effect1->shader());
          vl::ref<vl::TextureSampler> texture_sampler = new vl::TextureSampler;
          texture_sampler->setTexture(texture2);
          effect2->shader()->setRenderState(texture_sampler.get(), 0);

          vl::ref<vl::Geometry> box2 = vl::makeBox( vl::vec3(+7,5,0), 10,10,10);
          box2->computeNormals();
          mMainRendering->sceneManagers()->at(0)->as<vl::SceneManagerActorTree>()->tree()->addActor( box2.get(), effect2.get() );
        }
        else
        {
          // box #1
          vl::ref<vl::Geometry> box1 = vl::makeBox( vl::vec3(0,5,0), 10,10,10);
          box1->computeNormals();
          mMainRendering->sceneManagers()->at(0)->as<vl::SceneManagerActorTree>()->tree()->addActor( box1.get(), effect1.get() );
        }

      }

      // helper function
      vl::Actor* addActor(vl::Rendering* rendering, vl::Renderable* renderable, vl::Effect* eff, vl::Transform* tr)
      {
        return rendering->sceneManagers()->at(0)->as<vl::SceneManagerActorTree>()->tree()->addActor(renderable, eff, tr);
      }

      // populates ring scene on mRTT_Rendering
      void addRings(vl::GLSLProgram* glsl)
      {
        vl::ref<vl::Effect> effect = new vl::Effect;
        effect->shader()->setRenderState(glsl);
        vl::ref<vl::Light> light = new vl::Light;
        light->setAmbient( vl::fvec4( .1f, .1f, .1f, 1.0f) );
        light->setSpecular( vl::fvec4( .9f, .9f, .9f, 1.0f) );
        effect->shader()->setRenderState( light.get(), 0 );
        effect->shader()->enable(vl::EN_LIGHTING);
        effect->shader()->enable(vl::EN_DEPTH_TEST);
        effect->shader()->enable(vl::EN_CULL_FACE);
        effect->shader()->gocMaterial()->setDiffuse( vl::yellow );

        mTransfRing1 = new vl::Transform;
        vl::ref<vl::Geometry> ring1;
        ring1 = vl::makeTorus( vl::vec3(0,0,0), 10,0.5, 20,100);
        addActor(mRTT_Rendering.get(), ring1.get(), effect.get(), mTransfRing1.get());

        mTransfRing2 = new vl::Transform;
        vl::ref<vl::Geometry> ring2;
        ring2= vl::makeTorus( vl::vec3(0,0,0), 9,0.5, 20,100);
        addActor(mRTT_Rendering.get(), ring2.get(), effect.get(), mTransfRing2.get());

        mTransfRing3 = new vl::Transform;
        vl::ref<vl::Geometry> ring3;
        ring3= vl::makeTorus( vl::vec3(0,0,0), 8,0.5, 20,100);
        addActor(mRTT_Rendering.get(), ring3.get(), effect.get(), mTransfRing3.get());

        mTransfRing4 = new vl::Transform;
        vl::ref<vl::Geometry> ring4;
        ring4= vl::makeTorus( vl::vec3(0,0,0), 7,0.5, 20,100);
        addActor(mRTT_Rendering.get(), ring4.get(), effect.get(), mTransfRing4.get());

        mTransfRing5 = new vl::Transform;
        vl::ref<vl::Geometry> ring5;
        ring5= vl::makeTorus( vl::vec3(0,0,0), 6,0.5, 20,100);
        addActor(mRTT_Rendering.get(), ring5.get(), effect.get(), mTransfRing5.get());

        // update transform hierarchy every frame
        mRTT_Rendering->transform()->addChild(mTransfRing1.get());
        mTransfRing1->addChild(mTransfRing2.get());
        mTransfRing2->addChild(mTransfRing3.get());
        mTransfRing3->addChild(mTransfRing4.get());
        mTransfRing4->addChild(mTransfRing5.get());
      }

      virtual void initEvent()
      {
        vl::Log::notify(appletInfo());

        if (!vl::Has_FBO)
        {
          vl::Log::error("GL_ARB_framebuffer_object not supported.\n");
          vl::Time::sleep(2000);
          exit(1);
        }

        switch(mTestNum)
        {
        case 0: initTest_FBO_Render_To_Texture();
          break;
        case 1: initTest_FBO_Render_To_Texture_MRT();
          break;
        case 2: initTest_FBO_Render_To_Color_Buffer_And_Copy_To_Texture();
          break;
        case 3: initTest_FBO_Framebuffer_Blit_Multisample();
          break;
        case 4: initTest_FBO_Multisample_Texture();
          break;
        case 5: initTest_RTT_Legacy();
          break;
        default:
          break;
        }

        bindManipulators( mMainRendering->camera() );
      }

      void resizeEvent(int w, int h)
      {
        mMainRendering->camera()->viewport()->setWidth ( w );
        mMainRendering->camera()->viewport()->setHeight( h );
        mMainRendering->camera()->setProjectionPerspective();
      }

      virtual void updateScene()
      {
        mX  = vl::Time::currentTime() * 45*2;
        mY  = vl::Time::currentTime() * 45*2.1f;
        mX2 = vl::Time::currentTime() * 45*2.2f;
        mY2 = vl::Time::currentTime() * 45*2.3f;
        mX3 = vl::Time::currentTime() * 45*2.4f;

        mTransfRing1->setLocalMatrix( vl::mat4::getRotation(mX,  1,0,0) );
        mTransfRing2->setLocalMatrix( vl::mat4::getRotation(mY,  0,1,0) );
        mTransfRing3->setLocalMatrix( vl::mat4::getRotation(mX2, 1,0,0) );
        mTransfRing4->setLocalMatrix( vl::mat4::getRotation(mY2, 0,1,0) );
        mTransfRing5->setLocalMatrix( vl::mat4::getRotation(mX3, 1,0,0) );
      }

      virtual void destroyEvent()
      {
        BaseDemo::destroyEvent();

        // release all OpenGL resources
        setRendering(NULL);
        mMainRendering = NULL;
        mRTT_Rendering = NULL;
      }

    protected:
      int mTestNum;
      vl::real mX, mY, mX2, mY2, mX3;
      vl::ref<vl::Transform> mTransfRing1;
      vl::ref<vl::Transform> mTransfRing2;
      vl::ref<vl::Transform> mTransfRing3;
      vl::ref<vl::Transform> mTransfRing4;
      vl::ref<vl::Transform> mTransfRing5;
      vl::ref<vl::Rendering> mMainRendering;
      vl::ref<vl::Rendering> mRTT_Rendering;
    };

    // Have fun!

Visualization Library v2011.09.1162 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu Jan 26 2012 00:43:55.
Permission is granted to use this page to write and publish articles regarding Visualization Library.