Tutorial #5: Light effects
Please refer to tutorial #2 for instructions on how create a file structure and download the duck model.
The HTML document
Inside the mydemo folder, start by creating a simple html page.<html>
<head>
<title>Canvas3D tutorial #5: Light Effects</title>
<script type="application/javascript" src="../canvas3dapi/c3dapi.js" ></script>
<script type="application/javascript" src="tutorial5.js"></script>
</head>
<body>
<!-- Add a canvas element to the page. It is scripted by using its id -->
<canvas id="tutorial" style="border: 2px solid blue" width="500" height="500"></canvas>
</body>
</html>
The JavaScript Code
Place the following code in a file called tutorial5.js and place that in the mydemo folder (you can name the file differently but if you do so you will need to change the html to reflect this). Most of this code is the same as that in Tutorial #3. The changes are highlighted in bold.
Initially, the only difference is that we have turned the default ambient lighting off, but we’ll change this a little more as we go.
// Tutorial 5: the javascript
// The models used need to be parsed before the page
// render. This code will parse the model files
// and when this complete the parser will call the
// main. The argument being passed - "tutorial" -
// is the id of the canvas element on the html page.
c3dl.addMainCallBack(canvasMain, "tutorial");
c3dl.addModel("duck.dae");
var duck;
var timesincelastchange=0;
var y=-0.001;
// This callback function is used by the scene class. Every time
// the scene is updated, it will get called.
function spinduck(time){
// time is in milliseconds. Thus 3000 millisecond is 3 seconds.
timesincelastchange+=time;
//if its been 3 sec or more since we stopped or started the spinning
//change it.
if(timesincelastchange >=3000){
y = -1*y;
duck.setAngularVel(new Array(0.0,y,0.0));
timesincelastchange = 0;
}
}
// The program main
function canvasMain(canvasName){
// Create new c3dl.Scene object
scn = new c3dl.Scene();
scn.setCanvasTag(canvasName);
// Create GL context
renderer = new c3dl.WebGL();
renderer.createRenderer(this);
// Attach renderer to the scene
scn.setRenderer(renderer);
//Turn ambient lighting off
scn.setAmbientLight([0,0,0,0]);
scn.init(canvasName);
//the isReady() function tests whether or not a renderer
//is attached to a scene. If the renderer failed to
//initialize this will return false but only after you
//try to attach it to a scene.
if(renderer.isReady() )
{
// Create a Collado object that
// will contain a imported
// model of something to put
// in the scene.
duck = new c3dl.Collada();
// If the path is already parsed
// (as it is in this case)
// then the model is automatically retrieved
// from a collada manager.
duck.init("duck.dae");
// Give the duck a bit of a spin on y
duck.setAngularVel(new Array(0.0, -0.001, 0.0));
// Add the object to the scene
scn.addObjectToScene(duck);
// Create a camera
var cam = new c3dl.FreeCamera();
// Place the camera.
// WebGL uses a right handed co-ordinate system.
// move 200 to the right
// move 300 up
// move 500 units out
cam.setPosition(new Array(200.0, 300.0, 500.0));
// Point the camera.
// Here it is pointed at the same location as
// the duck so the duck will appear centered.
cam.setLookAtPoint(new Array(0.0, 0.0, 0.0));
// Add the camera to the scene
scn.setCamera(cam);
// add the callback function
scn.setUpdateCallback(spinduck);
// Start the scene
scn.startScene();
}
}
Types of light effect
No light
To begin with, the scene has no light. The model appears as a flat silhouette.
Ambient light
Through the normal default, there is ambient light throughout the scene. This light doesn’t appear to come from anywhere and doesn’t add the three dimensional feel of the scene, but it does allow everything in the scene to be seen. Without the other lights, the scene would appear flat.
To demonstrate, we’ll replace the code that turned ambient lighting off:
//Turn ambient lighting off scn.setAmbientLight([0,0,0,0]);with code that will explicitly set it to the colour we want:
//Turn ambient lighting on to weak gray light scn.setAmbientLight([0.3,0.3,0.3,1.0]);

Positional diffuse
This is a point light and radiates outward from its position like a lightbulb. This type of light will require a position and, since we’re making it diffuse, a diffuse colour.
so we’ll go back to the code that turned ambient lighting off:
//Turn ambient lighting off scn.setAmbientLight([0,0,0,0]);and we’ll add some code to add a positional diffuse light to the scene.
var diffuse = new c3dl.PositionalLight();
diffuse.setName('diffuse');
diffuse.setPosition([0,300,0]);
diffuse.setDiffuse([0.1,0.8,0.4,1]);
diffuse.setOn(true);
scn.addLight(diffuse);
Now tutorial5.js will look like this:
// Tutorial 5: the javascript
// The models used need to be parsed before the page
// render. This code will parse the model files
// and when this complete the parser will call the
// main. The argument being passed - "tutorial" -
// is the id of the canvas element on the html page.
c3dl.addMainCallBack(canvasMain, "tutorial");
c3dl.addModel("duck.dae");
var duck;
var timesincelastchange=0;
var y=-0.001;
// This callback function is used by the scene class. Every time
// the scene is updated, it will get called.
function spinduck(time){
// time is in milliseconds. Thus 3000 millisecond is 3 seconds.
timesincelastchange+=time;
//if its been 3 sec or more since we stopped or started the spinning
//change it.
if(timesincelastchange >=3000){
y = -1*y;
duck.setAngularVel(new Array(0.0,y,0.0));
timesincelastchange = 0;
}
}
// The program main
function canvasMain(canvasName){
// Create new c3dl.Scene object
scn = new c3dl.Scene();
scn.setCanvasTag(canvasName);
// Create GL context
renderer = new c3dl.WebGL();
renderer.createRenderer(this);
// Attach renderer to the scene
scn.setRenderer(renderer);
//Turn ambient lighting off
scn.setAmbientLight([0,0,0,0]);
scn.init(canvasName);
//the isReady() function tests whether or not a renderer
//is attached to a scene. If the renderer failed to
//initialize this will return false but only after you
//try to attach it to a scene.
if(renderer.isReady() )
{
// Create a Collado object that
// will contain a imported
// model of something to put
// in the scene.
duck = new c3dl.Collada();
// If the path is already parsed
// (as it is in this case)
// then the model is automatically retrieved
// from a collada manager.
duck.init("duck.dae");
// Give the duck a bit of a spin on y
duck.setAngularVel(new Array(0.0, -0.001, 0.0));
// Add the object to the scene
scn.addObjectToScene(duck);
// Create a camera
var cam = new c3dl.FreeCamera();
// Place the camera.
// WebGL uses a right handed co-ordinate system.
// move 200 to the right
// move 300 up
// move 500 units out
cam.setPosition(new Array(200.0, 300.0, 500.0));
// Point the camera.
// Here it is pointed at the same location as
// the duck so the duck will appear centered.
cam.setLookAtPoint(new Array(0.0, 0.0, 0.0));
// Add the camera to the scene
scn.setCamera(cam);
// add the callback function
scn.setUpdateCallback(spinduck);
var diffuse = new c3dl.PositionalLight();
diffuse.setName('diffuse');
diffuse.setPosition([0,300,0]);
diffuse.setDiffuse([0.1,0.8,0.4,1]);
diffuse.setOn(true);
scn.addLight(diffuse);
// Start the scene
scn.startScene();
}
}

Directional Diffuse
A directional light appears to come from an infinite distance and therefore lights all objects in the scene from the same angle. It is more like the Sun than a lightbulb. Since we’re still using diffuse light, it will need a diffuse colour, but unlike a positional light which has a position, a directional light has a direction. The direction is a vector that describes the angle at which the light will hit every object in the scene.
To achieve this we’ll replace:
var diffuse = new c3dl.PositionalLight();
diffuse.setName('diffuse');
diffuse.setPosition([0,300,0]);
diffuse.setDiffuse([0.1,0.8,0.4,1]);
diffuse.setOn(true);
scn.addLight(diffuse);
with:
var directional = new c3dl.DirectionalLight();
directional.setName('dir');
directional.setDirection([-2,3,-5]);
directional.setDiffuse([0.7,0.7,0.7,1]);
directional.setOn(true);
scn.addLight(directional);

Specular
Specular lighting is used to create shiny highlights as can be seen in the image below.

Unlike ambient and diffuse light, specular light takes not only the object’s position into account, but also the viewer’s position. This allows the shiny highlights to always ‘point’ to you. Like diffuse, this can be used with directional and/or positional lights, but we need to add a material to the object to specify how it will react to light before we can use this. That will have to wait until after we look at materials in tutorial #7.
