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();
mUseGLSL = GLEW_ARB_shading_language_100 != 0;
mDynamicLight = false;
mVolumeTr = new vl::Transform;
vl::VisualizationLibrary::rendering()->as<vl::Rendering>()->transform()->addChild( mVolumeTr.get() );
trackball()->setTransform( mVolumeTr.get() );
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() );
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() );
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() );
}
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());
mAlphaBias = mSlicedVolume->glslProgram()->getUniform("val_threshold");
mouseWheelEvent(0);
setVolume( vl::loadImage("/volume/VLTest.dat") );
}
void fileDroppedEvent(const std::vector<vl::String>& files)
{
if(files.size() == 1)
{
if (files[0].endsWith(".dat"))
{
vl::ref<vl::Image> vol_img = vl::loadImage(files[0]);
if (vol_img)
setVolume(vol_img);
}
}
else
{
std::vector<vl::String> files_sorted = files;
std::sort(files_sorted.begin(), files_sorted.end());
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]) );
vl::ref<vl::Image> vol_img = vl::assemble3DImage(images);
if (vol_img)
setVolume(vol_img);
}
}
void setVolume(vl::ref<vl::Image> img)
{
if(img->format() == vl::IF_LUMINANCE)
{
if (mUseGLSL)
{
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);
mSlicedVolume->setTransferFunction(trfunc.get());
mSlicedVolume->setVolumeImage(img.get());
mSlicedVolume->effect()->shader()->disable(vl::EN_ALPHA_TEST);
}
else
{
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));
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");
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);
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;
};