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]
Directional, Point and Spot Lights Tutorial

This tutorial demonstrates how to use the following light types: directional lights, point lights, spot lights, how to animate the position and direction of a light and how to attach a light to a camera.

[From App_Lights.cpp]

class App_Lights: public BaseDemo
{
public:
virtual void initEvent()
{
vl::Log::notify(appletInfo());
mCameraLightType = Disable;
// setup our simple scene with a plane and a few columns
mLightFx = new vl::Effect;
mLightFx->shader()->enable(vl::EN_LIGHTING); /* IMPORTANT! */
mLightFx->shader()->enable(vl::EN_DEPTH_TEST);
vl::ref<vl::Geometry> ground = vl::makeGrid( vl::vec3(0,0,0), 20, 20, 100,100 );
ground->computeNormals();
sceneManager()->tree()->addActor(ground.get(), mLightFx.get());
for(int i=0; i<9; ++i)
{
vl::ref<vl::Geometry> pillar = vl::makeCylinder( vl::vec3(6,2,-4*1.1f + i*1.1f), 1, 4, 100, 100, true, false);
pillar->computeNormals();
sceneManager()->tree()->addActor(pillar.get(), mLightFx.get());
}
for(int i=0; i<5; ++i)
{
vl::ref<vl::Geometry> pillar = vl::makeCylinder( vl::vec3(-3,2,-2*1.1f + i*1.1f), 1, 4, 100, 100, true, false);
pillar->computeNormals();
sceneManager()->tree()->addActor(pillar.get(), mLightFx.get());
}
// light setup
// A typical OpenGL implementation supports up to 8 lights at the same time. It means that your scene can have
// as many lights as you want but each object can be lit "only" by 8 lights at a time, this is usually never the
// case as lighting absorbs considerable computational resources.
// In our example each object will be lit up to 5 lights at the same time.
mLight0 = new vl::Light;
mLight1 = new vl::Light;
mLight2 = new vl::Light;
mLight3 = new vl::Light;
mLight4 = new vl::Light;
// Add the lights to the shader in order to use them (we save light #4 for the camera)
mLightFx->shader()->setRenderState( mLight0.get(), 0 );
mLightFx->shader()->setRenderState( mLight1.get(), 1 );
mLightFx->shader()->setRenderState( mLight2.get(), 2 );
mLightFx->shader()->setRenderState( mLight3.get(), 3 );
// Define the light diffuse color.
// See the OpenGL Programmer's Guide for more details about the OpenGL lighting model and equations.
mLight0->setDiffuse(vl::red);
mLight1->setDiffuse(vl::green);
mLight2->setDiffuse(vl::blue);
mLight3->setDiffuse(vl::white);
mLight4->setDiffuse(vl::white);
// Setup lights #0, #1 and #2 as positional lights with constant, linear and quadratic attenuation.
// Again, see the OpenGL Programmer's Guide for more details about the OpenGL lighting model and equations.
mLight0->setPosition(vl::fvec4(0,0,0,1)); /* default */
mLight0->setConstantAttenuation(1.0f);
mLight0->setLinearAttenuation(0.0f);
mLight0->setQuadraticAttenuation(0.0f);
mLight1->setPosition(vl::fvec4(0,0,0,1)); /* default */
mLight1->setConstantAttenuation(0.0f);
mLight1->setLinearAttenuation(1.0f);
mLight1->setQuadraticAttenuation(0.0f);
mLight2->setPosition(vl::fvec4(0,0,0,1)); /* default */
mLight2->setConstantAttenuation(0.0f);
mLight2->setLinearAttenuation(0.0f);
mLight2->setQuadraticAttenuation(1.0f);
// Setup light #3 as a spot light.
// Valid values are from 0.0f to 90.0f plus the special value 180.0f (default) which disables the spot lighting.
mLight3->setSpotCutoff(45.0f);
mLight3->setSpotExponent(5.0f);
mLight3->setSpotDirection(vl::fvec3(1,0,0));
// A spot light is essentially a special positional light so these apply to spot lights as well.
mLight3->setConstantAttenuation(1.0f);
mLight3->setLinearAttenuation(0.0f);
mLight3->setQuadraticAttenuation(0.0f);
// Setup light's Transform to animate them
mLight0_Transform = new vl::Transform;
mLight1_Transform = new vl::Transform;
mLight2_Transform = new vl::Transform;
mLight3_Transform = new vl::Transform;
rendering()->as<vl::Rendering>()->transform()->addChild(mLight0_Transform.get());
rendering()->as<vl::Rendering>()->transform()->addChild(mLight1_Transform.get());
rendering()->as<vl::Rendering>()->transform()->addChild(mLight2_Transform.get());
rendering()->as<vl::Rendering>()->transform()->addChild(mLight3_Transform.get());
// light 0..3 follow the relative transform
mLight0->bindTransform(mLight0_Transform.get());
mLight1->bindTransform(mLight1_Transform.get());
mLight2->bindTransform(mLight2_Transform.get());
mLight3->bindTransform(mLight3_Transform.get());
// light 4 follows the camera
mLight4->bindTransform(NULL);
// add a white sphere for each light to have a better visual feedback of the light animation.
bulb_fx->shader()->gocColor()->setValue(vl::white);
sceneManager()->tree()->addActor(bulb.get(), bulb_fx.get(), mLight0_Transform.get());
sceneManager()->tree()->addActor(bulb.get(), bulb_fx.get(), mLight1_Transform.get());
sceneManager()->tree()->addActor(bulb.get(), bulb_fx.get(), mLight2_Transform.get());
sceneManager()->tree()->addActor(bulb.get(), bulb_fx.get(), mLight3_Transform.get());
// Simple text to inform the user of the currently active light setup.
text_fx->shader()->enable(vl::EN_BLEND);
mText = new vl::Text;
mText->setFont( vl::defFontManager()->acquireFont("/font/bitstream-vera/VeraMono.ttf", 8) );
mText->setAlignment( vl::AlignHCenter | vl::AlignTop );
mText->setViewportAlignment( vl::AlignHCenter | vl::AlignTop );
mText->translate(0,-10,0);
sceneManager()->tree()->addActor(mText.get(), text_fx.get());
updateText();
}
void updateText()
{
switch(mCameraLightType)
{
case Disable: mText->setText("Camera light: Disable"); break;
case DirectionalLight: mText->setText("Camera light: Directional Light"); break;
case PositionalLight: mText->setText("Camera light: Positional Light"); break;
case SpotLight: mText->setText("Camera light: Spot Light"); break;
}
}
// Pressing space we cycle around 4 different light setup for light #4 (the one following the camera)
void keyPressEvent(unsigned short ch, vl::EKey key)
{
BaseDemo::keyPressEvent(ch, key);
if (key == vl::Key_Space)
{
mCameraLightType = (ECameraLightType)((mCameraLightType+1)%4);
switch(mCameraLightType)
{
case Disable:
// removes light #4 from the Shader
mLightFx->shader()->eraseRenderState(mLight4.get(), 4);
// you can also do:
// mLightFx->shader()->removeRenderState(vl::RS_Light4);
// or even
// mLightFx->shader()->removeRenderState(vl::Light(4).type());
break;
case DirectionalLight:
// add the light to the shader
mLightFx->shader()->setRenderState(mLight4.get(), 4);
// since the fourth component is 0 OpenGL considers this a direction
mLight4->setPosition(vl::fvec4(0,0,1,0));
// disable spot light
mLight4->setSpotCutoff(180.0f);
break;
case PositionalLight:
// add the light to the shader (just for clarity)
mLightFx->shader()->setRenderState(mLight4.get(), 4);
// since the fourth component is 1 OpenGL considers this a position
mLight4->setPosition(vl::fvec4(0,0,0,1));
// positional light attenuation
mLight4->setConstantAttenuation(1.0f);
mLight4->setLinearAttenuation(0.0f);
mLight4->setQuadraticAttenuation(0.0f);
// disable spot light
mLight4->setSpotCutoff(180.0f);
break;
case SpotLight:
// add the light to the shader (just for clarity)
mLightFx->shader()->setRenderState(mLight4.get(), 4);
// since the fourth component is 1 OpenGL considers this a position
mLight4->setPosition(vl::fvec4(0,0,0,1));
// positional light attenuation
mLight4->setConstantAttenuation(1.0f);
mLight4->setLinearAttenuation(0.0f);
mLight4->setQuadraticAttenuation(0.0f);
// enable and setup spot light
mLight4->setSpotCutoff(25.0f);
mLight4->setSpotExponent(40.0f);
mLight4->setSpotDirection(vl::fvec3(0,0,-1));
break;
}
}
updateText();
}
// Animate the lights
virtual void updateScene()
{
vl::real phase = 120.0f;
m.translate(5,1,0);
m.rotate( phase*0.0f + 1.0f*vl::Time::currentTime()*vl::fPi*15, 0, 1.0f, 0);
mLight0_Transform->setLocalMatrix(m);
m.translate(5,1,0);
m.rotate( phase*1.0f + 1.3f*vl::Time::currentTime()*vl::fPi*15, 0, 1.0f, 0);
mLight1_Transform->setLocalMatrix(m);
m.translate(5,1,0);
m.rotate( phase*2.0f + 1.7f*vl::Time::currentTime()*vl::fPi*15, 0, 1.0f, 0);
mLight2_Transform->setLocalMatrix(m);
m.rotate( 0.5f*vl::Time::currentTime()*vl::fPi*15, 0, 1.0f, 0);
mLight3_Transform->setLocalMatrix(m);
}
protected:
vl::ref< vl::Transform > mLight0_Transform;
vl::ref< vl::Transform > mLight1_Transform;
vl::ref< vl::Transform > mLight2_Transform;
vl::ref< vl::Transform > mLight3_Transform;
enum ECameraLightType { Disable, DirectionalLight, PositionalLight, SpotLight } mCameraLightType;
};
// Have fun!