Three.js: Moving Objects

Thought that I should write another post about my discoveries with the Three.js library as my last post was written sometime before Christmas. Having said that I didn’t make much progress with my Three.js investigations over the Christmas and New Year period. Quite a bit of time was spent pondering how to best implement an Object Orientated Programming approach with my JavaScript work.

In the end I elected to use the MooTools library; actually I’m only using the Class definition of that library so far. I’m just rather unimpressed with how classes, sorry reference types, are defined in JavaScript. Certainly when compared to how easily and seemingly naturally this is done with other modern languages. There seem to be a number of different techniques, or patterns, in use by the JavaScript community but in the end I decided to just use MooTools. I think that my main reason for electing to use the MooTools library was due to my desire to find out how to distinguish between private and public class members in JavaScript. I was doing some Googling one day and found something about how to define private class members with MooTools. I know this can be done without resorting to the use of a framework but sometimes I just want to get on with things and not worry about the boring details. Note to self: have a good look at the underlying principles of reference types in JavaScript sometime, e.g. the use of prototype.

So, I’ve been playing with a bit more of the Three.js library, been using the Tween.js library to perform some very simple movement and the Require.js library to bring everything together in a structured way.

Using the require.js library allows me to have just a single <script> tag in my HTML that references my main JavaScript file, namely main.js.

Managing JavaScript Files with require.js

Here’s the HTML.  The main point of interest here is the <script> tag I think. I’ve added some buttons to control the movement of the 3D object that I’ll discuss in a bit. I’m not going to apologise for the lack of styling and the ugly buttons; but I am sorry about that! In future posts I will attempt to make things a little tidier.

<!doctype html>
<html lang="en">
	<head>
		<title>A moving shape - Made with three.js</title>
		<meta charset="utf-8">
	</head>
	<body>

		<div id="container"></div>
		<div>
			<input type="button" id="fwdbtn" value="FWD"/>
			<input type="button" id="rotateleftbtn" value="ROTATE LEFT"/>
			<input type="button" id="rotaterightbtn" value="ROTATE RIGHT"/>
		</div>

		<script data-main="js/main" src="js/require.js"></script>

	</body>
</html>

Next is the JavaScript. Firstly is my main.js file that creates the 3D scene, adds objects to the scene and assigns event handlers to the buttons that were defined in the HTML previously. The first point of interest is the use of the require() function (line 1 in the main.js file shown below). I’m not going to discuss the details of the require.js library, suffice to say that this line ensures that the Character.js, Tween.js, RequestAnimationFrame.js, three.js and jquery.js dependency files are loaded before the inner function is executed. I’ve found that the use of the require.js library has given me the ability to place JavaScript code in smaller files rather than one large file and means that I don’t have to place numerous <script> tags in my HTML. There are many other benefits to using the require.js and I urge you to take a look at it.

Animating

I’ve attempted to place all code that deals with my movable object, or character as I have called it, in its own JavaScript file, Character.js. The Character.js file contains the definition of the Character class that is instantiated on line 4 below. Below this a little jQuery is used to bind methods of the Character class to click events on the buttons.

require(['96methods/Character', 'libraries/Tween', 'libraries/RequestAnimationFrame', 'libraries/Three', 'jquery'], function(Character) {

	var camera, scene, renderer;
	var character = new Character();

	// Add some button click event handlers:
	$("#rotateleftbtn").bind('click', character.rotateCharacterLeft);
	$("#rotaterightbtn").bind('click', character.rotateCharacterRight);
	$('#fwdbtn').bind('click', character.forwardCharacter);

	// Initialise and then animate the 3D scene!
	init();
	animate();

Following this is the init() method again as I’ve used previously in other posts (and in fact seems almost like the three.js standard). The key diferences between this version and what I did previously are rotating the camera so that it’s looking down upon the scene a little and using the createCharacter() method to add the ‘character’ object to the scene. Again this method is defined in the Character.js file (see later in this post).

Then come the animate() and render() function calls to perform the scene update; again as I’ve described in my previous post. The key difference here is the addition of the TWEEN.update() method call (line 79). TWEEN is yet another JavaScript library that I’m using to give me tweening functionality. Essentially everytime the animate() function is called the character object’s update method is called to reposition my character.

	function init() {

		// Instantiate the 3D scene:
		scene = new THREE.Scene();

		// Instantiate an Orthographic camera this time.
		// The Left/Right/Top/Bottom values seem to be relative to the scene's 0, 0, 0 origin.
		// The best result seems to come if the overall viewable area is divided in 2 and
		// the Left & Bottom values set to negative
		camera = new THREE.OrthographicCamera(
			window.innerWidth / -2, 	// Left
			window.innerWidth / 2,		// Right
			window.innerHeight / 2,		// Top
			window.innerHeight / -2,	// Bottom
			-2000,						// Near clipping plane
			1000 );						// Far clipping plane

		// Set the camera position so that it's up top and looking down:
		camera.position.y = 100;
		// Rotate around the x-axis by -45 degrees:
		camera.rotation.x -= 45 * (Math.PI/ 180);

		// Add the camera to the scene:
		scene.add(camera);

		// Define a cylinder object, well a cone anyway:
		cylinder = new THREE.Mesh(
			new THREE.CylinderGeometry(25,	// Radius top
				100,						// Radius bottom
				100,						// Height
				25,							// Number of segments in circumference (i.e. how smooth)
				5,							// Number of segments high
				false						// Open ended
			),
			new THREE.MeshBasicMaterial( {color: 0x372AFF} )
		);
		// Position it slightly to the right of the scene...
		cylinder.position.x = 400;
		// ...and add it to the scene:
		scene.add(cylinder);

		// Define our character shape and location within the scene:
		character.createCharacter(0, 0);
		// Add it to the stage:
		scene.add(character.getMesh());

		// Instantiate the renderer
		renderer = new THREE.CanvasRenderer();
		// .. and set it's size:
		renderer.setSize(window.innerWidth, window.innerHeight);

		// Place the renderer into the HTML (inside the #container div):
		$('#container').append(renderer.domElement);

	}

	function animate() {
		// Defined in the RequestAnimationFrame.js file, this function means that the
		// animate function is called upon timeout:
		requestAnimationFrame( animate );

		render();

		// Update the character position
		TWEEN.update();
	}

	function render() {

		// *** Update the scene ***
		renderer.render(scene, camera);
	}
});

As mentioned earlier, I’m trying to place all of the code that handles my moveable object in the character.js file, and therefore in my Character class.

There’s more require.js magic here to define my character module and specify the dependencies for this module, i.e. the three.js, mootools-core-1.4.2.js and Tween.js files. Once these files have been loaded a new instance of the Class object is returned (and thus available to the main.js file). Details of how the Class function works can be found in the MooTools documentation (see links later in this post).

Firstly a number of private member variables are declared and initialised then, to differentiate between private members and public members, the class is ‘appended’ to (at line 24 of character.js) specifying the public methods.

The getMesh() and setMesh() accessor methods are simply used to get/set the mesh data that is encapsulated within the Character class.

The createCharacter() method is responsible for instantiating the mesh for the character and setting its initial position in the 3D scene.

// 96methods/Character.js

// Character class definition

define(['libraries/three', 'libraries/mootools-core-1.4.2', 'libraries/Tween'], function() {

	return new Class(function() {

		// Private members
		var mesh = null;
		var width = 25, height = 25, length = 100;

		var tween = null;

		var currentAngle = { angle: 0 };
		var targetAngle = { angle: 45 };

		var currentZPos = { zPos: 0 };
		var targetZPos = { zPos: 100 };

		var actualAngle = 0;
		var actualZPos = 0;

		Object.append(this, {
			// Getters/setters
			getMesh: function() { return mesh; },
			setMesh: function(value) { mesh = value; },

			// Methods
			createCharacter: function(xpos, ypos) {
				mesh = new THREE.Mesh(
					new THREE.CubeGeometry(width, height, length),
					new THREE.MeshBasicMaterial( { color: 0x121212} ) // Material
				);

				mesh.position.x = xpos;
				mesh.position.z = ypos;
				mesh.position.y = 0;
			},

The forwardCharacter(), rotateCharacterLeft() and rotateCharacterRight() methods are bound to the buttons in the HTML and are responsible for controlling the movement of the character (ok it’s an oblong and not a well defined character but I’m taking small steps at a time here) when the buttons are clicked. If we focus on the rotateCharacterLeft() method:

			rotateCharacterLeft: function(event) {

				// Reset angle info:
				actualAngle = 0;
				currentAngle = { angle: 0 };

				// Define the tween along with the update function:
				tween = new TWEEN.Tween(currentAngle)
					.to(targetAngle, 1000)
					.onUpdate(function() {

						// Calculate the difference between current angle and where we want to be:
						var difference = Math.abs(currentAngle.angle - actualAngle);
						actualAngle = currentAngle.angle;

						// Rotate about Y:
						mesh.rotation.y += difference * (Math.PI / 180);
					})
					.start();
			},

The tween variable is assigned an instance of the Tween class; again see the Tween.js library (links a little later in this post). The argument to the Tween class’s constructor, currentAngle in this case, specifies the variable that will be used to track the current state of the animation as time progresses. The to() method then takes the target state and the time in milliseconds that the animation should take. In my example I’ve set the duration to 1000 milliseconds or 1 second. The onUpdate() method allows us to specify a callback function that is called when the TWEEN.update() method is called (see the animate() method of main.js shown earlier). In the case of the rotateCharacterLeft() method example the angle will be updated until it reaches the target angle of 45 degrees. Each time the callback function is called we calculate the difference between the current angle as determined by the tween and the actual angle the character is positioned at and move the character by this difference. The end result is that the character object rotates by 45 degrees in 1 second.

Here’s the remainder of the character.js file. The main point of interest here is in the forwardCharacter() method where the translateZ() method is used to move the character object, rather than rotating it.

			rotateCharacterRight: function(event) {

				// Reset angle info:
				actualAngle = 0;
				currentAngle = { angle: 0 };

				// Define the tween along with the update function:
				tween = new TWEEN.Tween(currentAngle)
					.to(targetAngle, 1000)
					.onUpdate(function() {

						// Calculate the difference between current angle and where we want to be:
						var difference = Math.abs(currentAngle.angle - actualAngle);
						actualAngle = currentAngle.angle;

						// Rotate about Y:
						mesh.rotation.y -= difference * (Math.PI / 180);
					})
					.start();
			},

			forwardCharacter: function(event) {

				// Reset z-pos info:
				actualZPos= 0;
			 	currentZPos = { zPos: 0 };

			 	tween = new TWEEN.Tween(currentZPos)
			 		.to(targetZPos, 1000)
			 		.onUpdate(function() {
						// Calculate the difference between current frame number and where we want to be:
						var difference = Math.abs(currentZPos.zPos - actualZPos);
						actualZPos = currentZPos.zPos;

						// Moving in -Z direction:
						mesh.translateZ(-difference);
			 		})
			 		.start();
			}

		}); // End of Object.append

	});
});

Summary

I’ve uploaded an example of the movable object to demonstrate the code discussed in this post. One of my colleagues pointed out to me recently that none of my examples worked in IE. I think this is because of the issues with Canvas on earlier versions of IE.

I also appreciate that the graphics that these brief examples reveal are far from being attractive. Ok, so they are ugly and primitive (yep, quite literally primitive)! I hope that, in future posts, that will be resolved. At the moment I’m just happy to be playing around with the technology and recording my discoveries.

I decided with this post to place links mostly at the end of the piece. The silly idea was to tempt people to read the whole post before clicking on links and leaving my site.

Full details of the require.js library can be found at the require.js site. I recall that I initially heard about this library on the excellent Think Vitamin site.

I happened across a post by Mark Joseph Obcena whilst searching for information on how best to implement private methods in JavaScript. This then led me to begin using the MooTools framework. I also came across David Walsh’s post about the combination of require.js and MooTools that you may find interesting reading. Documentation for the MooTools framework is also a good starting point.

The tween.js code can be found on github. I found out about this library/engine at the Learning Three.js site. I’ve recently found another tweening library by gskinner. I may need to look into this one at some point in the future.

If you’ve found this post useful or if you’ve constructive comments please add a comment or send me an email to let me know. It’s sometimes nice to know if anyone out there in web land finds any of this stuff useful.

4 Responses to Three.js: Moving Objects

  1. Dennis says:

    require.js creates script tags too.

    You only have a little bit smaller code in html file but round about 2000 lines of javascript in your RAM.

  2. Do you mind if I quote a few of your articles as long as I provide
    credit and sources back to your website? My blog is
    in the very same area of interest as yours and my visitors would truly benefit from some of the information you present here.

    Please let me know if this ok with you. Cheers!

    • gblake says:

      No problem at all. Thanks for asking and just be aware that my old posts are probably quite out of date now.

  3. kukuso says:

    Hello:

    I am trying to do the same example. But unfortunately I can’t do the same :(
    I think I put something wrong.
    Would you mind help me, please?
    And other question it’s possible to introduce the 3d model into iframe, that is to say, change the div “container” for iframe.

    Thank you.