Visualization Library 2.0.0

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

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
Shader Multipassing, LOD and Animation Tutorial

This tutorial shows some advanced techniques related to Shaders.

You will learn how to perform multipassing, how to define LODs (level of detail) in your Effects and how to animate your Shaders using the vl::ShaderAnimator class.

Visualization Library allows you to define quite intricate effects combination setups. You can in fact define several level of detail modes for your Effects. Each level of detail defines its own set of Shader passes, that is, VL will draw the object once for each pass using the corresponding Shader. And on top of all you can also animate your Shaders by defining a subclass of vl::ShaderAnimator and binding it to the Shader you want to animate!

The following example renders a simple scene with a few cubes. At LOD #0 the cubes are rendered using two passes. The firs pass renders the geometry using two textures out of which the second is animated using a roto-scaling effect. The second pass uses an animated outline blinking shader. At LOD #1 the cubes are rendered using two passes again. But in this case the first pass uses a simple non animated texture. The second pass uses again the outline blinking animated shader. At LOD #2 the cubes are rendered with a single pass using a simple texture.

[From App_ShaderMultiPassLODAnim.cpp]

#include "BaseDemo.hpp"
// color blinking effect
class BlinkShaderAnimator: public vl::ShaderAnimator
{
public:
void updateShader(vl::Shader* shader, vl::Camera*, vl::real cur_time)
{
int c = (int)( cur_time * 15.0 ) % 2;
vl::fvec4 color;
if (c == 0)
color = vl::gold;
else
color = vl::red;
shader->gocMaterial()->setFlatColor( color );
}
};
// texture roto-scale effect applied on the second texture unit
class TexRotScaleShaderAnimator: public vl::ShaderAnimator
{
public:
void updateShader(vl::Shader* shader, vl::Camera*, vl::real cur_time)
{
vl::fmat4 mat;
mat.translate(-0.5,-0.5,0.0f);
mat.rotate( cur_time * 90, 0, 0, 1 );
float s = 0.5f + (float)sin( cur_time * vl::fPi * 2.0f )*0.5f + 0.5f;
mat.scale( s, s, s );
mat.translate(+0.5,+0.5,0.0f);
shader->gocTextureMatrix(1)->setMatrix( mat );
}
};
// color fading effect
class MyShaderAnimator1: public vl::ShaderAnimator
{
public:
void updateShader(vl::Shader* shader, vl::Camera* , vl::real cur_time)
{
float t = (float)sin( cur_time*vl::fPi*2.0f )*0.5f + 0.5f;
vl::fvec4 col = vl::red*t + vl::blue*(1-t);
shader->gocMaterial()->setFlatColor(col);
}
};
/*
This demo shows how to use of the following techniques: shader LOD, shader animation, shader multipassing.
*/
class App_ShaderMultiPassLODAnim: public BaseDemo
{
public:
void initEvent()
{
vl::Log::notify(appletInfo());
// to be used later
// define LOD evaluator with 3 distance ranges: [0] --- 70 --- 100 --- [inf]
lod_eval->distanceRangeSet().push_back(70);
lod_eval->distanceRangeSet().push_back(100);
// texture roto-scaling effect
vl::ref<vl::Shader> tex_rot_scale_sh = new vl::Shader;
tex_rot_scale_sh->enable(vl::EN_DEPTH_TEST);
tex_rot_scale_sh->enable(vl::EN_CULL_FACE);
tex_rot_scale_sh->enable(vl::EN_LIGHTING);
tex_rot_scale_sh->setRenderState( light.get(), 0 );
texture = new vl::Texture("/images/holebox.tif", vl::TF_RGBA);
tex_rot_scale_sh->gocTextureSampler(0)->setTexture( texture.get() );
// on this unit we'll apply the roto-scale effect
texture = new vl::Texture("/images/star2.tif", vl::TF_RGBA);
tex_rot_scale_sh->gocTextureSampler(1)->setTexture( texture.get() );
// install shader animator
tex_rot_scale_sh->setShaderAnimator( new TexRotScaleShaderAnimator );
// simple texture effect
tex_sh->setRenderState( light.get(), 0 );
texture = new vl::Texture("/images/holebox.tif", vl::TF_RGBA);
tex_sh->gocTextureSampler(0)->setTexture( texture.get() );
// wireframe outline blinking shader
blink_sh->enable(vl::EN_LIGHTING);
blink_sh->setRenderState( light.get(), 0 );
blink_sh->gocFrontFace()->set(vl::FF_CW);
blink_sh->gocLineWidth()->set(3.0f);
// install shader animator
blink_sh->setShaderAnimator(new BlinkShaderAnimator);
// define the effect with 3 lods
effect->setLOD( 0, tex_rot_scale_sh.get(), blink_sh.get() ); // note multi-pass
effect->setLOD( 1, tex_sh.get(), blink_sh.get() ); // note multi-pass
effect->setLOD( 2, tex_sh.get() );
// install LOD evaluator
effect->setLODEvaluator(lod_eval.get());
// generate template geometry
// use the same texture coordinates for unit #0 and unit #1
box->setTexCoordArray(1, box->texCoordArray(0));
// form a ring with cubes
for(int i=0; i<24; ++i)
{
rendering()->as<vl::Rendering>()->transform()->addChild(tr.get());
vl::mat4 mat;
mat.translate(30,0,0);
mat.rotate( 360.0f / 20.0f * i, 0, 1, 0);
tr->setLocalMatrix( mat );
sceneManager()->tree()->addActor(box.get(), effect.get(), tr.get());
}
// add central cube
sceneManager()->tree()->addActor(box.get(), effect.get(), new vl::Transform);
}
// animate the scene
void updateScene()
{
vl::real t = sin( vl::Time::currentTime() * vl::fPi * 2.0f / 8.0f ) * 0.5f + 0.5f;
vl::vec3 eye( 130*t+5, t*20+5, 0 );
eye = vl::mat4::getRotation( vl::Time::currentTime() * 15.0f, 0, 1, 0 ) * eye;
vl::mat4 m = vl::mat4::getLookAt( eye, vl::vec3(0,0,0), vl::vec3(0,1,0) );
rendering()->as<vl::Rendering>()->camera()->setViewMatrix(m);
}
};
// Have fun!