Friday, October 4, 2013

Adding Lights with Three.js (part 2)

In the last post we looked at different types of lights and lighted materials in Three.js.  We then learned how to add a point light and change the material of the cube to correctly accept lighting.  Let's have some fun with the light object itself.  Just as you can manipulate the cube position/rotation (spinning),  and the camera position (as we did a while back), you can also change the light position dynamically in real time.
We will now essentially pick up the Sun (carefully - ouch!) and move it up in the sky to high noon, and back down again to sunset, back and forth over and over, like an outdoor time-lapse video on endless loop.  

We will take our trusty oscillation (back and forth) code that we learned a few posts back and use it to lift the sun up high, and then yank it back down again.  Take a look at the following oscillation code:

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 1;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 1;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }
This code should look familiar by now right?  All I did was change the variable names so it will work on our light position.  Our on/off switch, 'sunRiseFlag', will be turned to 'true' at the beginning of the program.  Looking at the code above, if 'sunRiseFlag' is equal to 'true', then the 'sunHeight' position variable will rise every animation frame.  If it gets to 150, which is a limit I chose, we cap it to 150 and then flip the 'sunRiseFlag' switch to 'false'.  Then if 'sunRiseFlag' is equal to 'false', we subtract 1 from the sunHeight variable every frame.  The Sun will now quickly set.  If it gets to 0, which is the ground level, we again cap it to 0, flip the switch back to 'true', and the Sun will rise again.  

Finally we just have to fill the actual light position variable with our 'sunHeight' variable.  Here's how we do that:
light.position.set(50,sunHeight,50);
We already saw this code in the last blog post, but notice the different variable that is in the y coordinate spot.  I took out the '50' that was there earlier, and replaced it now with our oscillating variable 'sunHeight'.  By doing this, we directly affect the light's position every animation frame.  And since we set the cube up to correctly receive lighting, we will now see it's lighted and shaded sides smoothly change as the Sun rises and sets.  
One more thing before we try out this example.  I took out the cube rotation code so that it will sit still.  This makes it easier to follow the lighted/shaded sides of the cube as the Sun moves up and down.  Since we don't need to animate the cube, I cut those rotation lines of code and moved them outside the animate() function.  They are now located nearer the top of the program.  Here's how these lines look now:
cube.rotation.x = 0.4;
cube.rotation.y = 0.6;
Notice that the addition ( + ) is gone now, and the rotation is just set one time only.  The cube will appear rotated already when you start the program, and it will stay there for the rest of the demo.  I chose 0.4 and 0.6 as the rotation numbers, but again, you can choose what you like.  I rotated the cube slightly like this so that we can see 3 of the different sides of the cube all at once, and better see how the cube reacts to the moving sunlight.    

Copy and Paste the following code and then save it as 'tempGame.js' , overwriting the old one:   

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var geometry = new THREE.CubeGeometry(1,1,1);
var material = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
light.position.set(50,0,50);
scene.add(light);

var sunRiseFlag = true;
var sunHeight = 0;

camera.position.z = 3;
cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

animate();

function animate(){
   
   requestAnimationFrame(animate);

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 1;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 1;
   }

   if(sunHeight > 150){
      sunHeight = 150;
      sunRiseFlag = false;
   }

   if(sunHeight < 0){
      sunHeight = 0;
      sunRiseFlag = true;
   }

   light.position.set(50,sunHeight,50);

   renderer.render( scene, camera );

}

Once you have saved it, go back to your example01.html file and open with your Chrome browser.  If you saved everything correctly, you should now see our old green cube slightly turned toward us and remaining still.  Meanwhile the sunlight on the right-hand side will quickly rise in the sky and then fall back down again, then rise, then fall, etc.  The cube will correctly respond to where the Sun is located in the sky, just like in reality.

We now have real-time dynamic lighting in our browsers!  This hopefully shows the cool effects we can make with just a few lines of code and the awesome Three.js library.  In part 3 of this Lighting post, we will add a yellow sphere object to our world so you can see where the Sun is located throughout the animation. 

continued in part 3...