Thursday, October 31, 2013

Adding Keyboard Input (part 2)

Now that we have included the new keyboard input helper file, how do we access it?  Well, Jerome Etienne designed his 'threex.keyboardstate.js' to work a lot like Three.js does, so we should feel comfortable using it. 

Open up our 'tempGame.js' file and add the following line near the top:    
var keyboard = new THREEx.KeyboardState();
That looks familiar doesn't it?  There IS a small difference however in this variable declaration.  Notice the small letter 'x' placed right after the word 'THREE' .  This tells us that the variable 'keyboard' will be using the new THREEx library rather than the older THREE library that we have had since the beginning of our project.  Other than that, it's identical in syntax, so we should feel right at home.

The 'keyboard' object now holds all the properties and functionality designed by Jerome to aid us in scanning the player's keyboard for keypresses in real time.  And since we want our game to quickly scan the keyboard on every animation frame (as fast as it can), we will put the actual scanning code inside the animation function.  Here's how the new keyboard scanning code lines look:
if( keyboard.pressed("D") ){
 cube.position.x = cube.position.x + 60 * frameTime;
}
Let's take a look at each line above.  Remember our 'if( )' statement a while back.  This 'if' statement tests for whether something is true or not.  And what we want to test for is if the user is pressing the 'D' key on their keyboard.  Jerome has designed a function for the keyboard object called '.pressed(" ")' .  Inside the double quotes we place the key on the keyboard that we want to test for.  In this case it's the 'D' key, so we type 'keyboard.pressed("D")' .  This will return 'true' if the 'D' key is pressed, and 'false' if it is not pressed.

Also recall that if the test comes back as 'true', then the 'if' statement will execute whatever is inside its curly braces { }.  In this case I have put a line of code to move our green cube's position to the right (positive x).  I chose '60' because it is medium-fast and looked good for this demo (feel free to experiment with this number).  Notice I also put ' * frameTime; ' at the end.  Get used to doing this for every line of code that deals with motion or animation.  Using 'frameTime' like this on all the game's moving objects will make sure that it looks the same on everyone's computer, no matter what the specs are for their device.

All that's left to do now is add the tests for the other 3 keys : the W, A, and S keys.  Here's how the whole thing looks now:
if( keyboard.pressed("D") ){
   cube.position.x = cube.position.x + 60 * frameTime;
}
if( keyboard.pressed("A") ){
   cube.position.x = cube.position.x - 60 * frameTime;
}
if( keyboard.pressed("W") ){
   cube.position.y = cube.position.y + 60 * frameTime;
}
if( keyboard.pressed("S") ){
   cube.position.y = cube.position.y - 60 * frameTime;
}
The above statements test for the 4 keys that most games use as input: the WASD keys.  Looking at each case above, the 'D' key will move the cube right (positive x), the 'A' key will move the cube left (negative x), the 'W' key will move the cube up (positive y) and the 'S' key will move the cube down (negative y).  

What's really cool is that Jerome's keyboard helper also can handle multiple keypresses.  So, if you hold down 'D' and 'A' at the same time, the +60 and -60 will cancel each other out, and you will see the cube stop.  If you hold the 'D' and the 'W' key at the same time, the cube will combine movement right (+60) and up (+60) at the same time, which is diagonally upper-right motion.  We now have 8 possible movement directions!  Thinking in a clockwise manner, they are: up, upper-right, right, lower-right, down, lower-left, left, and upper-left.  

All we have to do now is add all the above lines back into our tempGame.js file.  Copy and Paste the following code and 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 clock = new THREE.Clock();

var keyboard = new THREEx.KeyboardState();

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

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

var sunRiseFlag = true;
var sunHeight = 0;
var frameTime = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

animate();

function animate(){
   
   requestAnimationFrame(animate);

   frameTime = clock.getDelta();

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 60 * frameTime;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 60 * frameTime;
   }

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

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

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

   
   if( keyboard.pressed("D") ){
 cube.position.x = cube.position.x + 60 * frameTime;
   }
   if( keyboard.pressed("A") ){
 cube.position.x = cube.position.x - 60 * frameTime;
   }
   if( keyboard.pressed("W") ){
 cube.position.y = cube.position.y + 60 * frameTime;
   }
   if( keyboard.pressed("S") ){
 cube.position.y = cube.position.y - 60 * frameTime;
   }

   renderer.render( scene, camera );
   
}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}

Go back and open the example01.html file with your browser.  If you saved everything correctly, you should see our new help text at the top of the webpage that reads: "Press W, A, S, and D keys to move the cube".  And when you press them - the cube moves!  We now have a responsive, interactive graphics demo.  It is not a game yet, but we are getting there.

I should note that this demo only works on desktops and laptops that have a physical keyboard attached.  For smart phones and tablets, we will have to figure out how to handle touch input on those devices.  We want ALL users to be able to play our games right?  Luckily, there are some libraries and helper routines that we can quickly add to make the demos/games work on mobile devices as well.  We will take a look at those in the near future. 

It's pretty awesome though that we only added about 10 lines of code and now we have user input, making our demo truly interactive.  That is the magic of JavaScript and helper libraries!

In the next posts we will add debug/info text to the top left-hand corner of our webpage that will tell us the number values of any game object that we want to inspect more closely.  This is really helpful when monitoring game performance, game variables that are quickly changing, and also when something isn't quite working how we want - it can help us correct any problems that come up. 

See you soon!

Wednesday, October 30, 2013

Adding Keyboard Input (part 1)

At this point we have the makings of a fun graphics demo, but it is not responsive yet for the player.  Other than re-sizing the browser window, the user has no way of interacting with our program.  It's time to remedy that!  What we will do in this post is add a simple keyboard input file to our project.  When we've done that, our demo (future game) will respond to keyboard key-presses in real time.   

You may recall back when we added the Three.js library file to our project, I said that it makes our 3D game programming lives much easier.  Three.js takes care of the not-so-fun raw GL graphics / math initialization for us, so that we can focus on the fun stuff.   However, Three.js is meant to only aid in 3D graphics rendering inside the browser.  It purposefully leaves out libraries of keyboard/mouse/touch input, AI, networking, game physics, audio, and other various components that we might need for our future games.  If it DID include all those, the Three.js library would grow into a huge, unmanageable file that would be slow to download over the internet for people wanting to try our games. Rather, Three.js focuses on just the rendering so that you, the programmer, can add in different components only as you need them.  This makes your game projects just big enough to work correctly, but not too big because of unused features and unnecessary components.  And everyone's component needs will vary, depending on their type of project, so this makes sense.

So now we have to add in our own keyboard input code.  We could try this from scratch, but why re-invent the wheel?  If someone has already coded it and packaged it up nicely for you, why not use it?   There are all sorts of additional helper files and functions floating around out there on the internet that are meant to be used in conjunction with Three.js.  These smaller, specialized files take care of various tasks that aren't inside the main Three.js library (like handling user keyboard input).  In fact, one such brave programmer has made it his mission to help everyone in their Three.js journey.  His name is Jerome Etienne from Paris, France.  He has been kind enough to create and share small helper files for Three.js and game programming in general.  And one of these files is devoted to Keyboard input, which we need.  

Click on the following link and after the new page loads, Right-Click on the webpage and Save As... 'threex.keyboardstate.js'  . Save this inside the 'js' folder where our 'tempGame.js' and 'three.min.js' are already located.  

threex.keyboardstate.js

Now you should have a total of 3 different .js (JavaScript) files in your 'js' folder : tempGame.js, three.min.js, and now threex.keyboardstate.js  .  This last file we just added to our project is kind of like a 'plugin' for game programming in the browser.  Thanks to Jerome's fine work, his helper file will allow us to query the keyboard for keypresses in real time.  We can then use this information to move the characters/objects in our game and make it truly interactive!

We haven't changed our old 'example01.html' file in a while; but we need to update it now because the browser has to be able to locate the new 'threex.keyboardstate.js' file that we just added to our project.   

Do you remember how to include a new JavaScript file in html?  We do it with the 'script' tag like this:      
<script src="js/threex.keyboardstate.js"></script> 
With the addition of the above line, we will have 3 different lines with the script tag, each loading in a different component (or dependency).  At this point, it's worth noting that the 3 script lines must be placed in the right order, otherwise we'll get errors in the browser console and our game won't work correctly.  Take a look below at our new example01.html file and how I ordered the 3 script tag lines: 

<!DOCTYPE html>
<html>
   <head>
      <title> Hello Three.js </title>
   </head>
   <body>
      <script src="js/three.min.js"></script>
      <script src="js/threex.keyboardstate.js"></script> 
      <script src="js/tempGame.js"></script>     
   </body>
</html>

If you follow each script line from top to bottom, this .html code first loads the most important library, 'three.min.js' .  Then it loads our new helper file, 'threex.keyboardstate.js'.  Lastly, it loads our 'tempGame.js' which holds the future game code that we are writing.  This file is dependent on the other two .js files to be already in place, so it must be loaded last.

While we have this .html file open, there's one more thing I want to add.  It will be a line of text that is placed at the top of our webpage that instructs the user what to do, and what keys to press.  It is like a mini help file and I really appreciate when others add it to their demos/games, so we will do it too.

Here's how to add a line of text using the html 'div' tag:
<div id="help" style="position:fixed; left:40%; top:4%; color:grey;"> 
         Press W, A, S, and D keys to move the cube 
</div>
This 'div' (short for 'division') element has an id named "help".  I chose that because it is descriptive of what this 'div' does.  Next we set the style by typing style = " " and inside the double quotes we put key:value pairs.  First comes the key/attribute followed by a colon ( : ) and then its value.  A semicolon ( ; ) follows each pair.  Then comes the next pair and so on.  The first key:value pair is 'position:fixed;' .  This sets the text to a fixed position on the webpage so that it is in relation to the browser window itself and not some other element on the page.  Next comes 'left:40%;' which pushes the left margin of the text over to 40% the width of the webpage (which is almost half way over).  Similarly, 'top:4%;' pushes the top margin down just a little, 4% down the webpage.  Finally, 'color:grey;' sets the text color to a stock grey.  
On the next line we type 'Press W, A....' which is the actual content of our text.  These instructions will make it more clear what to do for first-time users.  

Here is the updated example01.html file with our new 'div' text element and our new 'script' tag line which includes the keyboard helper library to our project: 

<!DOCTYPE html>
<html>
   <head>
      <title> Hello Three.js </title>
   </head>
   <body>
      <div id="help" style="position:fixed; left:40%; top:4%; color:grey;"> 
         Press W, A, S, and D keys to move the cube 
      </div>

      <script src="js/three.min.js"></script>
      <script src="js/threex.keyboardstate.js"></script> 
      <script src="js/tempGame.js"></script>     
   </body>
</html>

Copy and paste the above code and save it as 'example01.html', writing over the old one.  In part 2 of this post, we will actually use this new keyboard helper in our tempGame.js file.  We will then have a truly interactive demo!  See you in the next part!

(Continued in part 2)...

Friday, October 18, 2013

Timing on Different Systems with Three.js

Let's consider the effect of timing on games.   Typically, all moving game objects and players/characters are updated every cycle through the game code.  This means that if you instruct the game to "move a character/object by 1 unit", it will indeed move by 1 unit on every pass through your game program.  
 Take our sun light object for example.  On every frame of animation we want its height to move smoothly, so we type:
sunHeight = sunHeight + 1;
Just like we expect, the sun will rise smoothly, and it will work on any computing device or smartphone.  That's all good, until you consider that not everyone's device is running at the same rate.  A powerful desktop computer might loop through this statement 60 times a second, while a smartphone or old computer might only get around to it 20 times a second.  That means that the person playing your game on their powerful desktop computer will see and feel a different game experience than the person playing on a smartphone or older computer system. 

How do we fix this problem?  We turn to time-based animation.  Essentially we measure how fast the user's system is looping through our game code per second, and then we multiply that time delay by the game objects' speed.  Here's how the above example will look now:
sunHeight = sunHeight + 1 * frameTime;
In the above snippet, the 'sunHeight' variable is still being raised at 1 unit every animation frame, just like before.  But now we have multiplied this amount by a new variable called 'frameTime'.  'frameTime' holds the amount of time it took for the user's system to complete 1 animation loop.  And this 'frameTime' value is continually refreshed on each loop through our game code (as we all know, computers can have performance hiccups now and then).  As with racing times, and your cholesterol, lower numbers are better for 'frameTime' - and higher numbers are worse.  A good computing system will quickly lap around your program, giving a lower frameTime.  A smaller or older device will take longer to do those laps around your code and will result in a higher number for frameTime.  But not to worry if you are one of the users of the less powerful systems!  The above equation is the great equalizer when it comes to game performance. 

To see how, let's imagine running through the above code with a fast computer. The 'frameTime' result will be a lower number.  Let's say it clocks out at 16 milliseconds, which is around 0.016 seconds. So  after the multiplication is performed, 'sunHeight' in this instance gets a small number added to it every frame and smoothly rises on our screen.  Now run the same game on an old computer or phone, and their 'frameTime' result may be as high as 50 milliseconds, or 0.05 seconds.  So after the multiplication is performed, 'sunHeight' in this instance gets a larger number added to it every animation frame.   This little 'frameTime' equation gives the slower computers a boost, so that they catch up to the faster computers.   If you put the fast and the slow systems side-by-side, the game's objects will move at the same rate!

The only downside to all this is that the slower computers will look a little more choppy and less-smooth than the faster computers, because the slower devices have to cover more ground each animation frame to catch up.  But the important thing is that all players of our games, regardless of their system specs, will see and feel the same game timing and movement that we wanted them to experience!   Just think if we could apply this method to Olympic racing athletes; all countries would be winners - actually they would all tie for the Gold medal!  :-)

The next order of business is somehow timing the end-user's system each animation loop so that we can apply the right amount of boost.  Three.js to the rescue!  The folks on the Three.js team have provided us with the perfect tool for this very purpose:  the 'THREE.Clock()' object. 

Here's how we declare a new clock variable in our game code: 
var clock = new THREE.Clock();

This kind of Three.js declaration should look familiar by now, right?  We name a variable 'clock' and fill it by typing '= new' and a call to the 'THREE.Clock()' object.  Now the variable 'clock' has all the accuracy and functionality of a real-life digital stopwatch that can measure how fast something is running.  To use it, we have to declare one more variable - the 'frameTime' variable that we saw earlier.  That's easily done by typing:
var frameTime = 0;
We initially set 'frameTime' equal to 0.  Then, as the game program runs, it will be refreshed every animation frame, so it will correctly hold the results of the system's performance.

One last thing to do is sample the 'clock' object every frame, so we get an accurate timing measurement.  In Three.js, this is accomplished by typing:
frameTime = clock.getDelta();
'frameTime' is now filled using the equals ( = ) sign and a call to one of our 'clock' object's helper functions, called getDelta.  So we type 'clock.getDelta();'  Delta is a mathematical term for how much something has changed - in this case how much the time has changed (or how much time has gone by).  A smaller Delta means a little time has passed, and a bigger Delta means a larger amount of time has passed.  

One more thing to mention is that when applying this equation to our old sunHeight code, it moved too slowly, compared with how it used to move before our changes.  So I had to tweak the initial speed of the sunHeight variable to something bigger.  It used to be 1, as in:
sunHeight = sunHeight + 1 * frameTime;
But now it is: 
sunHeight = sunHeight + 60 * frameTime;

I know that's a big jump in the speed amount, but it actually works out to look the same as our old example.  That's because 'frameTime' on most decent computers comes back with really small numbers, making the overall sunHeight movement very small.  Using the old number '1', the Sun light crawled up too slowly.  However with a simple change to '60', and after the new frameTime calculation, it moves very much like we intended it to do, which is pretty fast up and down in the sky.  If you wanted a realistic simulation of the Sun rising, you could try '0.05' or something.  It will rise VERY slowly.  You would have to wait all day to see the results!

I've included our new clock and frameTime code in the tempGame.js file.  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 clock = new THREE.Clock();

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

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

var sunRiseFlag = true;
var sunHeight = 0;
var frameTime = 0;

camera.position.y = 40;
camera.position.z = 160;

cube.rotation.x = 0.4;
cube.rotation.y = 0.6;

animate();

function animate(){
   
   requestAnimationFrame(animate);

   frameTime = clock.getDelta();

   if(sunRiseFlag == true){
      sunHeight = sunHeight + 60 * frameTime;
   }

   if(sunRiseFlag == false){
      sunHeight = sunHeight - 60 * frameTime;
   }

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

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

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

   renderer.render( scene, camera );

}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}


Once you have saved it, go back to your example01.html file and open with your Chrome browser.  Now the yellow Sun light will move up and down smoothly on your device.  And no matter what system you are running this code on, the Sun will reach high noon and sunset at exactly the same time for you.  If you are running this on an old device or a less-powerful smartphone, it might appear a little choppy.  But the important thing to note is that our future games will animate with the same timing, and the gameplay will be consistent and positive for everyone!

Till next time... 

Tuesday, October 15, 2013

Handling Window Re-sizing in the Browser

It's time to do a little house-keeping maintenance on our game template.  I know, that doesn't sound as exciting as player movement and dynamic lighting, but it is just as important.  What we are looking to do in this post is learn how to handle when the user suddenly changes the browser window size.  This happens quite frequently, so we need to have code in place to quickly re-size our game graphics too.  Otherwise, our viewport will get stretched out of proportion or it might get cut off so the user cannot see the whole picture.  Let's take a look at how to keep the browser view centered and in proportion.

  Every webpage on the internet has a global 'window' object that contains the entire webpage.  The 'window' is like the trunk of a tree and our game is somewhere out on the branches.  Everything on our webpage is connected back to the 'window' object.  The window object is created for us when we open a browser, and it comes with some helpful functions.  One of these is called 'addEventListener()'.  This helper function listens for events such as mouse clicks, window re-sizing, etc..  When it detects that one of these user events has happened, it performs a function of your choosing.  This way, your webpage will become interactive and responsive to the user's actions.  

Here's how to create an eventListener on the window object of our webpage:  
window.addEventListener('resize', onWindowResize, false); 

We type 'window' which refers to the browser window object, then a period ( . ) which is about to call a function on that object, then 'addEventListener();'  You'll notice that this function takes 3 parameters inside its parentheses ( ). The first, 'resize', is telling the browser what we want to listen for - in this case, a browser window re-size by the user. The second parameter, 'onWindowResize' , is the name of our function that will be executed if a 'resize' is detected.  Don't worry about the third parameter which is set to 'false'.  This is an optional parameter that we can leave out, but the W3C advises to put it in anyway to be compatible with older browsers.  

We will define our 'onWindowResize' function now. When the browser detects that a re-size has happened, it will look for a function called 'onWindowResize' and execute whatever code is inside that function.  So at the bottom of our program, we will add the definition of this 'onWindowResize' function.  Here's how the definition looks: 
function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}

Think of the above code snippet as a 'design' for a function.  This code does nothing on its own - it only provides the instructions of what to do if it is called.  You can also tell that this is just a design by looking at the final curly brace ( } ) by itself on the very last line.  Notice it does not have a semi-colon ( ; ) after it.  So it's not really an action statement that just happens on its own.  This function has to be called by something else.  And that something else is our 'addEventListener' that we just created inside the window object.  When addEventListener detects a browser re-size, it will find this 'onWindowResize' function and execute all the code inside of its curly braces.  
Let's take a look at each line of code inside this function.  The first line accesses the 'aspect' property of the 'camera' that we created at the top of the program.  Remember 'aspect' means the ratio of width to height of your computer/device screen.  This first line fills the 'aspect' property with the new width and height of the browser window, now that the user has suddenly changed them.  
The next line calls a function on our camera object called 'updateProjectionMatrix()' .  Without getting too technical, this helper function recalculates the camera's viewing frustum (a sort of pyramid with the pyramid top at your eye location, the sides extending outward from you, and the pyramid base located back in the distance where you are looking).
The final line should look familiar.  It is an exact copy of our initial renderer set-up code.  This call just refreshes everything so that the final image is correct.

And that's it!  Now that we have everything we need to handle re-sizing, let's add this code back into our game template.  Here's how the final tempGame.js file looks now.  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);
window.addEventListener('resize', onWindowResize, false); 

var cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

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

var sunRiseFlag = true;
var sunHeight = 0;

camera.position.y = 40;
camera.position.z = 160;

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);
   sphere.position = light.position;

   renderer.render( scene, camera );

}


function onWindowResize(){
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );   
}

Once you have saved it, go back to your example01.html file and open with your Chrome browser.  Now while the Sun is moving up and down, try to drag the window edges of your browser around.  Try minimizing, maximizing, and squashing the dimensions of the browser window.  No matter what you do now, our code will efficiently handle these window 're-sizes' and correctly display our game graphics.  Pretty handy!

Next up... Timing on different users' machines with the Three.js Clock.  

Tuesday, October 8, 2013

Adding Lights with Three.js (part 3)

At this point, we have our green cube responding correctly to an off-screen light source that is moving up and down.  In this final part of "Adding Lights with Three.js", we will learn how to create a yellow sphere (representing the Sun) and place it where the light is coming from.  Then we will pull back the camera a bit so we can see the cube being lit while the yellow Sun is moving up and down, all in the same view.

First let's see how to make a yellow sphere with Three.js.  Here's how it looks:  
var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);
In the first line, we name a variable 'sphereGeometry' that will hold the design or blueprint of the sphere shape.  We fill this variable using the equals sign ( = ) and a call to THREE.SphereGeometry();  This function takes a number of optional parameters inside its parentheses.  For now, we will only use the most important one, which is size.  This size parameter represents how big the sphere's radius will be.  I arbitrarily chose '5' units for the radius.  You can try other values if you like and see how it affects the scene.  
On the next line we name a variable 'sphereMaterial' which will hold the information about the sphere's material or skin.  Since the Sun itself does not have a shadow, but rather glows bright yellow on all sides, we can just use 'MeshBasicMaterial' (which has no shading) that we used a while back for the green cube.  For the rgb color parameter, we use '255,255,0' which is the rgb code for the brightest yellow. 
The final 2 lines above should look familiar.  We create a mesh variable called 'sphere' that will hold the combination of the Sun's shape (sphereGeometry) and skin (sphereMaterial).  The var 'sphere' now represents everything we need to know about the Sun object.  One last thing to do - add the Sun to our scene.  That is accomplished by typing 'scene.add(sphere);'. 

Inside the animate() loop we will set this newly created sphere to be located exactly where the light source is located.   We do this by typing:
sphere.position = light.position; 
That's pretty intuitive right? Now our Sun sphere will move exactly with the light position as it moves up and down. 

Before we try out this example in the browser,  I want to tell you about some minor changes that I made to make all of the objects fit inside the view at the same time.   First I pulled the camera back so we can see the Sun go all the way up.  So now the camera.position.z variable is set to 160 units (+Z goes behind you which is what we want).  Also, in order to see the Sun sphere rise all the way to the top, I moved the camera up as well.  Remember that the +Y axis goes up.  So now we set the camera.position.y to 40 units.
Here's how the new camera position lines look now:
camera.position.y = 40;
camera.position.z = 160;
One last minor change:  when pulling the camera back like this, I found I couldn't see the green cube very well anymore - it was too small in the distance.  So I just increased the original dimensions of the cube to 20 units on all sides (it was 1 before).   

Well, that covers all the changes.  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 cubeGeometry = new THREE.CubeGeometry(20,20,20);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(5);
var sphereMaterial = new THREE.MeshBasicMaterial({ color: 'rgb(255,255,0)' });
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

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

var sunRiseFlag = true;
var sunHeight = 0;

camera.position.y = 40;
camera.position.z = 160;

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);
   sphere.position = light.position;

   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 see our green cube, now a little farther away, being lit up by the rising and setting Sun sphere object.  This little demo proves that the light is indeed coming from exactly where the yellow sphere is located, which is physically accurate.

Hopefully you are starting to get the hang of creating new Three.js objects, whether they be cubes, spheres, or lights.  We will return to lighting later in this blog series.  But in the next posts, we are going to add some code that will re-size and re-center our view correctly, in case the user suddenly changes their browser window dimensions.  We will also take a look at timing and the Three.js Clock object for handling faster vs. slower computers efficiently, so that everyone,  regardless of their system that they are running our future games on, will have a good experience.

Stay tuned!

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...

Tuesday, October 1, 2013

Adding Lights with Three.js (part 1)

Now it's time for one of the most important elements in 3D games and graphics:  lights and lighting.   The Three.js library offers us some of the latest and most realistic lighting and shading options available in today's web browsers.   There are a lot of options for types of lights, types of surface materials on the subjects that are lit,  and equations/algorithms that affect the final look of the lighted scene.  This will be a multi-part post because we have to cover quite a bit of setup for lighting to work well in Three.js.  
First, we have to change the material (or skin) of our colored cube so that it will correctly respond to lights in the game world.  If you recall, here is the old way of setting up the material/skin of our green-colored cube:
var material = new THREE.MeshBasicMaterial({ color: 'rgb(0,255,0)' });
Unfortunately, this way of setting up a 'Basic' material will only shade the cube with the rgb color that you manually give to it. It will not respond to lighting situations like a cube would in real life.  It was fun a couple of posts ago, when we manually changed the color from dark to bright red, but to achieve realistic lighting and shading, we have to change the material.  Here is the new way of declaring our material/skin:  
var material = new THREE.MeshLambertMaterial({ color: 'rgb(0,255,0)' });
It almost looks the same doesn't it?  The only word that has changed is the 'Basic' is now replaced with 'Lambert'.  Without getting too deep into lighting theory and algorithms, 'Lambert' is a lighting/shading mathematical model that takes the value of the incoming light (it's intensity and angle of approach) and shades the sides of our cube accordingly.  Let's say we have the Sun rising on our right-hand side.  And we are looking straight ahead toward a cube sitting on the ground in front of us.  Since the Sun is on the right, the cube's right side will be brightly lit, while its left-hand sides that are facing away from the Sun will be darker, or in shadow.  The Lambert model does all the lighting math for us and appropriately shades the cube.
There are many other lighting mathematical models out there, but for now we will stick with Lambert because it is fast and efficient.  Later we will also look at the 'Phong' model, which is even more realistic because it calculates specular reflections (highlights on shiny surfaces) as well.  But it is more taxing on your device's display/graphics card, so we will use the 'Phong' model only sparingly in the future.

We now have a material skin that will respond to lights.  But if we were to run the program, our green cube would appear black on all sides!  This is because the 'Lambert' material needs a light source for us to see anything.  Lights in Three.js are declared and set up much like everything else in Three.js.  The only difference is that Three.js lights take some different parameters inside the parentheses ( ) that I will explain in a moment.  Here's what the light setup code looks like:
var light = new THREE.PointLight( 'rgb(255,255,255)', 1, 0 );
By now most of this coding style should look familiar.  We use the 'var' keyword followed by a descriptive name for our light object, in this case 'light'.  Then we fill it by typing ' = new ' followed by a call to THREE.PointLight(); A point light in 3D graphics is a light source that has a definite position or location in the world.  Think of it as a really bright light-bulb.  In the real world, a light-bulb emits light in all directions equally.  And in the real world you can pick up a light-bulb and place it anywhere you want.  The same holds true for the 'PointLight' in Three.js.  It radiates light outward in all directions, and we can later specify the PointLight's location using its x, y, and z coordinates.
A Three.js 'PointLight' accepts optional parameters inside its parentheses when you first declare it in your program. These are: ( 'Color', Intensity, and Falloff-distance ).  Looking at the above code example, I typed 'rgb(255,255,255)' for the Color parameter, which is the rgb code for the brightest white color possible. Next I typed a '1' for the Intensity parameter (which can range from 0 to 1), meaning I want this to be a strong, powerful light source (think of the Sun).  Lastly I put a '0' for the Falloff distance parameter.  This means I don't want any Falloff at all, specified by a '0' in Three.js.  To explain; every light source in the real world has a falloff-distance at which the light runs out and becomes too weak to substantially light up a surface.  For computer games played in an Earth environment, the Sun point light has no falloff-distance and for us humans it is equally bright no matter where we move to on the Earth.  Technically, if we were to blast off in a super-fast spaceship and get really far away from the Sun, we would begin to notice it does have a falloff where it can no longer provide light and warmth for us.  But for all practical purposes, we can assume that games modeled with the Sun in mind, have the light source as not falling off at all, so we use a '0' for this parameter.  However, if you wanted to have a tiny LED light or light-bulb in your game, this realistically does have a noticeable falloff distance.  So, to create that type of light, we would type '100' (or similar value) for the Falloff-distance parameter, which sets the reaches of the light to no more than 100 units.  The power/intensity of the light will also smoothly decrease as it reaches this outer limit.   This means that if you start traveling away from the light source, it will get darker and darker around you, and if you go out farther than '100' units from the light, you will be in total darkness.

Next, we must position our new PointLight in the game world.  We do this by using the name we gave it, then typing '.position.set(x,y,z); '  - where 'x,y,z' are the coordinates where you would like the light to be located at.  Let's say that we want to pick up the light and move it to the right of us, and a little upwards in the sky, and a little bit behind our backs.  All values in this case will be positive numbers.  Remember that positive X goes to the right, positive Y goes up, and positive Z goes behind you. Here's what this light positioning looks like in code:
light.position.set(50,50,50);
In the above code snippet, we type the name of our light, which is 'light', followed by '.position' which accesses the light's position property, followed by '.set( )' which sets the location of the light source.  Inside the parentheses, I put '50' for the x, y, and z coordinates, thus moving the light right, upward, and behind us.  In the next post we will tinker with these numbers to dynamically move the light (the Sun) up and down.

Finally we have to add our newly created 'light' to the scene, so that it can start lighting up the game objects. Here's how that looks:  
scene.add(light);
Remember that 'scene' is the name we gave to our Three.js scene at the beginning of the program.  At this point, we have added both the 'cube' and the 'light' now to the 'scene' object.  Because we have added everything, Three.js will do its magic with the help of the 'Lambert' lighting model and correctly shade our green-colored cube.  I removed the camera animation code from earlier examples, so that the cube will just sit in one place and rotate smoothly.  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,50,50);
scene.add(light);

camera.position.z = 3;
animate();

function animate(){
   
   requestAnimationFrame(animate);

   cube.rotation.x = cube.rotation.x + 0.02;
   cube.rotation.y = cube.rotation.y + 0.03;

   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 see our old green cube now magically lit by artificial sunlight - pretty cool!  And since we placed the light source on the right, upward, and behind us, the right side of the cube and the top of the cube is more brightly lit than the left and bottom, which are in shadow.

In part 2 we will use our trusty oscillation code to move the Sun quickly up and down, and watch how it affects the shading of the cube.  Although, we mustn't let all this power of moving Suns go to our heads!  :-) 

continued in part 2...