# Visualization Library

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

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

# Volume Rendering with Transfer Functions and Lighting Tutorial

This tutorial demonstrates how to use how to render volume data, how to apply custom transfer functions and lighting.

[From `App_VolumeRendering.hpp`]

    class App_VolumeRendering: public BaseDemo
    {
    public:
      virtual void initEvent()
      {
        BaseDemo::initEvent();

        // general test setup
        mUseGLSL      = GLEW_ARB_shading_language_100 != 0;
        mDynamicLight = false; // for GLSL mode only

        // transform and trackball steup
        mVolumeTr = new vl::Transform;
        vl::VisualizationLibrary::rendering()->as<vl::Rendering>()->transform()->addChild( mVolumeTr.get() );
        trackball()->setTransform( mVolumeTr.get() );

        // volume
        vl::AABB volume_box( vl::vec3(-10,-10,-10), vl::vec3(+10,+10,+10) );
        mSlicedVolume = new vlVolume::SlicedVolume;
        mSlicedVolume->setTransform(mVolumeTr.get());
        mSlicedVolume->setBox(volume_box);
        mSlicedVolume->setRenderRank(1);
        sceneManager()->tree()->addActor( mSlicedVolume.get() );

        // volume_box outline
        vl::ref<vl::Effect> fx_box = new vl::Effect;
        fx_box->shader()->gocPolygonMode()->set(vl::PM_LINE, vl::PM_LINE);
        fx_box->shader()->enable(vl::EN_DEPTH_TEST);
        vl::ref<vl::Geometry> box_outline = vlut::makeBox(volume_box);
        box_outline->setColorArray(vlut::red);
        sceneManager()->tree()->addActor( box_outline.get(), fx_box.get(), mVolumeTr.get() );

        // light bulb

        if (mDynamicLight)
        {
          mLight = mSlicedVolume->light();
          mLightTr = new vl::Transform;
          vl::VisualizationLibrary::rendering()->as<vl::Rendering>()->transform()->addChild( mLightTr.get() );
          mLight->followTransform( mLightTr.get() );

          vl::ref<vl::Effect> fx_bulb = new vl::Effect;
          fx_bulb->shader()->enable(vl::EN_DEPTH_TEST);
          vl::ref<vl::Geometry> light_bulb = vlut::makeIcosphere(vl::vec3(0,0,0),1,1);
          sceneManager()->tree()->addActor( light_bulb.get(), fx_bulb.get(), mLightTr.get() );
        }

        // bias text
        mBiasText = new vl::Text;
        mBiasText->setFont( vl::VisualizationLibrary::fontManager()->acquireFont("/font/bitstream-vera/VeraMono.ttf", 12) );
        mBiasText->setAlignment( vl::AlignHCenter | vl::AlignBottom);
        mBiasText->setViewportAlignment( vl::AlignHCenter | vl::AlignBottom );
        mBiasText->translate(0,5,0);
        mBiasText->setBackgroundEnabled(true);
        mBiasText->setBackgroundColor(vl::fvec4(0,0,0,0.75));
        mBiasText->setColor(vlut::white);
        vl::ref<vl::Effect> effect = new vl::Effect;
        effect->shader()->enable(vl::EN_BLEND);
        sceneManager()->tree()->addActor(mBiasText.get(), effect.get());

        // bias uniform
        mAlphaBias = mSlicedVolume->glslProgram()->getUniform("val_threshold");

        // update alpha bias text
        mouseWheelEvent(0);

        setVolume( vl::loadImage("/volume/VLTest.dat") );
      }

      void fileDroppedEvent(const std::vector<vl::String>& files)
      {
        if(files.size() == 1) // if there is one file load it directly
        {
          if (files[0].endsWith(".dat"))
          {
            vl::ref<vl::Image> vol_img = vl::loadImage(files[0]);
            if (vol_img)
              setVolume(vol_img);
          }
        }
        else // if there is more than one file load all the files and assemble a 3D image
        {
          // sort files by their name
          std::vector<vl::String> files_sorted = files;
          std::sort(files_sorted.begin(), files_sorted.end());
          // load the files
          std::vector< vl::ref<vl::Image> > images;
          for(unsigned int i=0; i<files_sorted.size(); ++i)
            images.push_back( vl::loadImage(files_sorted[i]) );
          // assemble the volume
          vl::ref<vl::Image> vol_img = vl::assemble3DImage(images);
          // set the volume
          if (vol_img)
            setVolume(vol_img);
        }
      }

      void setVolume(vl::ref<vl::Image> img)
      {
        if(img->format() == vl::IF_LUMINANCE)
        {
          if (mUseGLSL) // use GLSL
          {
            vl::Log::info("IF_LUMINANCE image and GLSL supported: lighting and the transfer function will be computed in realtime.\n");
            vl::ref<vl::Image> trfunc = vl::Image::makeColorSpectrum(128, vlut::black, vlut::blue, vlut::green, vlut::yellow, vlut::red);
            // enables GLSL usage
            mSlicedVolume->setTransferFunction(trfunc.get());
            mSlicedVolume->setVolumeImage(img.get());
            mSlicedVolume->effect()->shader()->disable(vl::EN_ALPHA_TEST);
          }
          else // precompute transfer function and illumination
          {
            vl::Log::info("IF_LUMINANCE image and GLSL not supported: transfer function and lighting will be precomputed.\n");
            vl::ref<vl::Image> trfunc = vl::Image::makeColorSpectrum(128, vlut::black, vlut::blue, vlut::green, vlut::yellow, vlut::red);
            vl::ref<vl::Image> volume = vlVolume::SlicedVolume::genRGBAVolume(img.get(), trfunc.get(), vl::fvec3(1.0f,1.0f,0.0f));
            // disable GLSL usage
            mSlicedVolume->setTransferFunction(NULL);
            mSlicedVolume->setVolumeImage(volume.get());
            mSlicedVolume->effect()->shader()->enable(vl::EN_ALPHA_TEST);
            mSlicedVolume->effect()->shader()->gocAlphaFunc()->set(vl::FU_GEQUAL, 0.3f);
          }
        }
        else
        {
          vl::Log::info("Non IF_LUMINANCE image: not using GLSL.\n");
          // disable GLSL usage
          mSlicedVolume->setTransferFunction(NULL);
          mSlicedVolume->setVolumeImage( img.get() );
          mSlicedVolume->effect()->shader()->enable(vl::EN_ALPHA_TEST);
          mSlicedVolume->effect()->shader()->gocAlphaFunc()->set(vl::FU_GEQUAL, 0.3f);
        }

        mAlphaBias->setUniform(0.3f);
        updateText();
        openglContext()->update();
      }

      void updateText()
      {
        float bias = 0.0f;
        mAlphaBias->getUniform(&bias);
        mBiasText->setText(vl::Say("Bias = %n") << bias);
      }

      void mouseWheelEvent(int val)
      {
        float alpha = 0.0f;
        mAlphaBias->getUniform(&alpha);
        alpha += val * 0.01f;
        alpha =  vl::clamp(alpha, 0.0f, 1.0f);
        mAlphaBias->setUniform(alpha);

        // used for non GLSL mode volumes
        mSlicedVolume->effect()->shader()->gocAlphaFunc()->set(vl::FU_GEQUAL, alpha);

        updateText();
        openglContext()->update();
      }

      virtual void run()
      {
        if (mDynamicLight)
        {
          vl::mat4 mat = vl::mat4::rotation( vl::Time::currentTime()*45, 0,0,1 ) * vl::mat4::translation(20,0,0);
          mLightTr->setLocalMatrix(mat);
        }
      }

      protected:
        vl::ref<vl::Transform> mVolumeTr;
        vl::ref<vl::Transform> mLightTr;
        vl::ref<vl::Uniform> mAlphaBias;
        vl::ref<vl::Text> mBiasText;
        vl::ref<vl::Light> mLight;
        bool mDynamicLight;
        bool mUseGLSL;
        vl::ref<vlVolume::SlicedVolume> mSlicedVolume;
    };

    // Have fun!

Visualization Library v2009.07 Reference Documentation
Copyright 2005-2009 Michele Bosi. All rights reserved.
Updated on Mon Aug 10 21:41:31 2009.
Permission is granted to use this page to write and publish articles regarding Visualization Library.