Creating the maze and animating the cube

Exclusive offer: get 50% off this eBook here
Three.js Essentials

Three.js Essentials — Save 50%

Create and animate beautiful 3D graphics with this fast-paced tutorial book and ebook.

$19.99    $10.00
by Jos Dirksen | July 2014 | Open Source Web Development

This article by Jos Dirksen, the author of Three.js Essentials, describes how to create a maze and animate a cube using Three.js.

(For more resources related to this topic, see here.)

A maze is a rather simple shape that consists of a number of walls and a floor. So, what we need is a way to create these shapes. Three.js, not very surprisingly, doesn't have a standard geometry that will allow you to create a maze, so we need to create this maze by hand. To do this, we need to take two different steps:

  1. Find a way to generate the layout of the maze so that not all the mazes look the same.
  2. Convert that to a set of cubes (THREE.BoxGeometry) that we can use to render the maze in 3D.

There are many different algorithms that we can use to generate a maze, and luckily there are also a number of open source JavaScript libraries that implement such an algorithm. So, we don't have to start from scratch. For the example in this book, I've used the following random-maze-generator project that you can find on GitHub at the following link:

https://github.com/felipecsl/random-maze-generator

Generating a maze layout

Without going into too much detail, this library allows you to generate a maze and render it on an HTML5 canvas. The result of this library looks something like the following screenshot:

You can generate this by just using the following JavaScript:

var maze = new Maze(document, 'maze'); maze.generate(); maze.draw();

Even though this is a nice looking maze, we can't use this directly to create a 3D maze. What we need to do is change the code the library uses to write on the canvas, and change it to create Three.js objects. This library draws the lines on the canvas in a function called drawLine:

drawLine: function(x1, y1, x2, y2) { self.ctx.beginPath(); self.ctx.moveTo(x1, y1); self.ctx.lineTo(x2, y2); self.ctx.stroke(); }

If you're familiar with the HTML5 canvas, you can see that this function draws lines based on the input arguments. Now that we've got this maze, we need to convert it to a number of 3D shapes so that we can render them in Three.js.

Converting the layout to a 3D set of objects

To change this library to create Three.js objects, all we have to do is change the drawLine function to the following code snippet:

drawLine: function(x1, y1, x2, y2) { var lengthX = Math.abs(x1 - x2); var lengthY = Math.abs(y1 - y2); // since only 90 degrees angles, so one of these is always 0 // to add a certain thickness to the wall, set to 0.5 if (lengthX === 0) lengthX = 0.5; if (lengthY === 0) lengthY = 0.5; // create a cube to represent the wall segment var wallGeom = new THREE.BoxGeometry(lengthX, 3, lengthY); var wallMaterial = new THREE.MeshPhongMaterial({ color: 0xff0000, opacity: 0.8, transparent: true }); // and create the complete wall segment var wallMesh = new THREE.Mesh(wallGeom, wallMaterial); // finally position it correctly wallMesh.position = new THREE.Vector3( x1 - ((x1 - x2) / 2) - (self.height / 2), wallGeom.height / 2, y1 - ((y1 - y2)) / 2 - (self.width / 2)); self.elements.push(wallMesh); scene.add(wallMesh); }

In this new drawLine function, instead of drawing on the canvas, we create a THREE.BoxGeometry object whose length and depth are based on the supplied arguments. Using this geometry, we create a THREE.Mesh object and use the position attribute to position the mesh on a specific points with the x, y, and z coordinates. Before we add the mesh to the scene, we add it to the self.elements array.

Now we can just use the following code snippet to create a 3D maze:

var maze = new Maze(scene,17, 100, 100); maze.generate(); maze.draw();

As you can see, we've also changed the input arguments. These properties now define the scene to which the maze should be added and the size of the maze. The result from these changes can be seen in the following screenshot:

Every time you refresh, you'll see a newly generated random maze. Now that we've got our generated maze, the next step is to add the object that we'll move through the maze.

Animating the cube

Before we dive into the code, let's first look at the result as shown in the following screenshot:

Using the controls at the top-right corner, you can move the cube around. What you'll see is that the cube rotates around its edges, not around its center. In this section, we'll show you how to create that effect. Let's first look at the default rotation, which is along an object's central axis, and the translation behavior of Three.js.

The standard Three.js rotation behavior

Let's first look at all the properties you can set on THREE.Mesh. They are as follows:

Function/property

Description

position

This property refers to the position of an object, which is relative to the position of its parent. In all our examples, so far the parent is THREE.Scene.

rotation

This property defines the rotation of THREE.Mesh around its own x, y, or z axis.

scale

With this property, you can scale the object along its own x, y, and z axes.

translateX(amount)

This property moves the object by a specified amount over the x axis.

translateY(amount)

This property moves the object by a specified amount over the y axis.

translateZ(amount)

This property moves the object by a specified amount over the z axis.

If we want to rotate a mesh around one of its own axes, we can just call the following line of code:

plane.rotation.x = -0.5 * Math.PI;

We've used this to rotate the ground area from a horizontal position to a vertical one. It is important to know that this rotation is done around its own internal axis, not the x, y, or z axis of the scene. So, if you first do a number of rotations one after another, you have to keep track at the orientation of your mesh to make sure you get the required effect. Another point to note is that rotation is done around the center of the object—in this case the center of the cube. If we look at the effect we want to accomplish, we run into the following two problems:

  • First, we don't want to rotate around the center of the object; we want to rotate around one of its edges to create a walking-like animation
  • Second, if we use the default rotation behavior, we have to continuously keep track of our orientation since we're rotating around our own internal axis

In the next section, we'll explain how you can solve these problems by using matrix-based transformations.

Creating an edge rotation using matrix-based transformation

If we want to perform edge rotations, we have to take the following few steps:

  • If we want to rotate around the edge, we have to change the center point of the object to the edge we want to rotate around.
  • Since we don't want to keep track of all the rotations we've done, we'll need to make sure that after each rotation, the vertices of the cube represent the correct position.
  • Finally, after we've rotated around the edge, we have to do the inverse of the first step. This is to make sure the center point of the object is back in the center of the cube so that it is ready for the next step.

So, the first thing we need to do is change the center point of the cube. The approach we use is to offset the position of all individual vertices and then change the position of the cube in the opposite way. The following example will allow us to make a step to the right-hand side:

cubeGeometry.applyMatrix(new THREE.Matrix4().makeTranslation (0, width / 2, width / 2)); cube.position.y += -width / 2; cube.position.z += -width / 2;

With the cubeGeometry.applyMatrix function, we can change the position of the individual vertices of our geometry. In this example, we will create a translation (using makeTranslation), which offsets all the y and z coordinates by half the width of the cube. The result is that it will look like the cube moved a bit to the right-hand side and then up, but the actual center of the cube now is positioned at one of its lower edges. Next, we use the cube.position property to position the cube back at the ground plane since the individual vertices were offset by the makeTranslation function.

Now that the edge of the object is positioned correctly, we can rotate the object. For rotation, we could use the standard rotation property, but then, we will have to constantly keep track of the orientation of our cube. So, for rotations, we once again use a matrix transformation on the vertices of our cube:

cube.geometry.applyMatrix(new THREE.Matrix4().makeRotationX(amount);

As you can see, we use the makeRotationX function, which changes the position of our vertices. Now we can easily rotate our cube, without having to worry about its orientation. The final step we need to take is reset the cube to its original position; taking into account that we've moved a step to the right, we can take the next step:

cube.position.y += width/2; // is the inverse + width cube.position.z += -width/2; cubeGeometry.applyMatrix(new THREE.Matrix4().makeTranslation(0, - width / 2, width / 2));

As you can see, this is the inverse of the first step; we've added the width of the cube to position.y and subtracted the width from the second argument of the translation to compensate for the step to the right-hand side we've taken.

If we use the preceding code snippet, we will only see the result of the step to the right.

Summary

In this article, we have seen how to create a maze and animate a cube.

Resources for Article:


Further resources on this subject:


Three.js Essentials Create and animate beautiful 3D graphics with this fast-paced tutorial book and ebook.
Published: July 2014
eBook Price: $19.99
Book Price: $32.99
See more
Select your format and quantity:

About the Author :


Jos Dirksen

Jos Dirksen has worked as a software developer and architect for more than a decade. He has quite a lot of experience in a large range of technologies that range from backend technologies, such as Java and Scala, to frontend development using HTML5, CSS, and JavaScript. Besides working with these technologies, he also regularly speaks at conferences and likes to write about new and interesting technologies on his blog. He also likes to experiment with new technologies and see how they can be best used to create beautiful data visualizations, the results of which you can see on his blog at http://www.smartjava.org/.

Jos currently works as an enterprise architect for Malmberg, a large Dutch publisher of educational material. He helps to create a new digital platform for the creation and publication of educational content for primary, secondary, and vocational education. Previously, he worked in many different roles in the private and public sectors, ranging from private companies such as Philips and ASML to organizations in the public sector, such as the Department of Defense.

Jos has already written a book on Three.js named Learning Three.js: The JavaScript 3D Library for WebGL,Packt Publishing, which is an in-depth description of all the features Three.js provides. Besides his interest in frontend JavaScript and HTML5 technologies, he is also interested in backend service development using REST and traditional web service technologies. He has already written two books on this subject. He is the co-author along with Tijs Rademakers of Open-Source ESBs in Action, Manning Publications, an action book that was published in 2008. In 2012, he published a book on how to apply SOA Governance in a practical manner, titled SOA Governance in Action, Manning Publications.

Books From Packt


Game Development with Three.js
Game Development with Three.js

Learning Three.js: The JavaScript 3D Library for WebGL
Learning Three.js: The JavaScript 3D Library for WebGL

Leap Motion Development Essentials
Leap Motion Development Essentials

Instant Migration to HTML5 and CSS3 How-to
Instant Migration to HTML5 and CSS3 How-to

HTML5 Graphing and Data Visualization Cookbook
HTML5 Graphing and Data Visualization Cookbook

HTML5 and CSS3 Transition, Transformation, and Animation
HTML5 and CSS3 Transition, Transformation, and Animation

3ds Max Speed Modeling for 3D Artists
3ds Max Speed Modeling for 3D Artists

3D Game Development with Microsoft Silverlight 3: Beginner's Guide
3D Game Development with Microsoft Silverlight 3: Beginner's Guide


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software