Getting Started with WebGL and Three.js

Written by Greg Stier
on October 12, 2012

What is WebGL?

WebGL is a Javascript API used to render 2D and 3D graphics to the screen in a browser. Programming directly in the WebGL API can be very complicated and messy, but lucky for us there are libraries that simplify this. One such library is Three.js.

Three.js is a lightweight 3D library that hides a lot of the WebGL complexities and makes it very simple to get started with 3D programming on the web.

Three.js can be downloaded from github, where you will also find links to documentation and examples.

In this tutorial I’m going to show you how to set-up a basic Three.js application. The application I’m going to create is not going to be earth shattering by any means, but it will give you a great starting point for learning the basics of 3D animation in the web.

To view this demonstration, you will need a WebGL compatible browser. If you have a recent version of Chrome, Firefox, or Safari, you should be good to go. If you are running Internet Explorer, you may be out of luck.

You can view the result of this tutorial here, and the source code can be found here.

Setting the Stage

Walk into any theatre and you will find three basic components that are needed to create a great show: a stage, lights and actors. Creating 3D animation is no different.

In Three.js, the camera is what is used to define the stage. The camera tells Three.js what the height, width, and depth of the stage is. When setting up a camera, it is easiest to imagine a pyramid with the tip of the pyramid starting at the camera. The vertical field of view tells Three.js the total height the camera can see. The aspect ratio is the width of the field of view. The near plane and the far plane set the camera’s depth of view. Taking a look at the diagram below, the black dot represents the camera. The small blue plane is the near plane and the large blue plane is the far plane. Only objects inside the pyramid between the two blue planes will be visible and rendered. All objects that lie outside of the pyramid will not be visible.

Getting Started

We begin with a very simple HTML file that will load our Three.js application. As you can see, the following HTML assumes that you have downloaded the minified three.js library and saved it in a folder named ‘js’. I’ve also created my application, three-tut.js, and saved it in the same location.

<!DOCTYPE html>
<html>
<head>
<title>WebGL/Three.js Step Tutorial</title>
<style>
body {
margin: 0px;
background-color: #fff;
overflow: hidden;
}
</style>
</head>
<body>
<script src="js/three.min.js"></script>
<script src="js/three-tut.js"></script>
</body>
</html>

Once I have my HTML file created, I start with a basic template for writing my application. My template consists of three functions. The init() function is where I will do all of the setup required to render the scene. The second function is the animate() function. This function is where I will update the state of each object in the scene that I want to animate. The third function is the render() function. This function will contain code that will render the results of the state changes from the animate() function.

function init() {
}
function animate() {
}
function render() {
}

Before I begin implementing the init() function, l am going to add a few more lines of code to the top of my application javascript file:

var camera;
var scene;
var renderer;

init();

The above code is simple enough. I have created holders for the basic Three.js components: the camera, the scene, and the renderer. Then I make a call to the init() function.

Let’s begin setting the scene. Inside the init() function I create a scene object.

scene = new THREE.Scene();

Next I’m going to create a camera object. As I said before, the camera is what is used to set the dimensions of the stage.

camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000);

The above line of code creates a camera with a perspective projection. The four arguments are as follows:

  1. The camera frustum vertical field of view
  2. The camera frustum aspect ratio
  3. The camera frustum near plane
  4. The camera frustum far plane

Next I’m going to create a light and add it to the scene.

var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 ).normalize();
scene.add(light);

The first line creates a directional light that gives off a white light. The second line tells Three.js at what angle the light will shine by giving it an x, y, and z coordinate. Finally, I add the light to the scene.

If you were to run the application right now you would see nothing, as I haven’t added any objects to the scene. Let’s go ahead and add an object to the scene.

Every object that is rendered in Three.js is called a Mesh. A mesh consists of two main components. The first component of a mesh is the geometry. A geometry is the shape we want to draw on the screen. It consists of vertices and faces. Three.js comes with some basic geometries so l am going to start with one of those. I’m going to use a cube. The cube will have a width, height, and depth of 10.

var geometry = new THREE.CubeGeometry(10, 10, 10);

The next component of a mesh is a material. A material is used to describe the appearance of objects. It is used to describe things like the color, shading, transparency, and shininess of the objects. Again, Three.js comes with a set of pre-built materials, so I’ll use one of those.

var material = new THREE.MeshPhongMaterial( { ambient: 0x050505, color: 0x0033ff, specular: 0x555555, shininess: 30 } );

Now that I have the two necessary components of a mesh, I can build a mesh and add it to the scene.

var mesh = new THREE.Mesh(geometry, material );
mesh.position.z = -50
scene.add( mesh );

In the first line above I create the mesh with the geometry and material that I previously created. The mesh has a default position of x=0, y=0, and z=0. This is also the default position of the camera, so the second line in the code above moves the mesh a distance of 50 away from the camera.

In Three.js the coordinate system works as follows. Point (0,0,0) is the center of the world. As you look at your screen, positive x values move to the right and negative x values move to the left. Positive y values move up and negative y values move down. Positive z values move toward you and negative z values move away from you.

Finally, the third line adds the mesh to the scene.

You could run the application now, but you will still not see anything on the screen. This is because we need to create a renderer so Three.js knows how to render the scene. Three.js can render the scene in multiple different ways. It can render the scene using SVG, Canvas, or WebGL. We are using WebGL.

Finally I’m going to finish the init() function. Add the following code to the bottom of the init() function:

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

The first line of code creates a WebGL renderer. The second line of code sets the size of the renderer; in this case I’m using the entire screen. The third line of code attaches the renderer to the body of the HTML, and the last line of code calls my render function.

So far this is what our code looks like:

var camera;
var scene;
var renderer;

init();
animate();

function init() {

scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000);

var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 ).normalize();
scene.add(light);

var geometry = new THREE.CubeGeometry( 10, 10, 10);
var material = new THREE.MeshPhongMaterial( { ambient: 0x050505, color: 0x0033ff, specular: 0x555555, shininess: 30 } );

mesh = new THREE.Mesh(geometry, material );
mesh.position.z = -50
scene.add( mesh );

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

render();
}

function animate() {
}

function render() {
}

I need to add one last line of code before we can see the cube on the screen. I am going to add the following to the render() function:

renderer.render( scene, camera );

Our render function now looks like this:

function render() {
renderer.render( scene, camera );
}

If you open the HTML file now, you should see a very boring blue square on the screen.

Now that we have an object on the screen, let’s do something with it to show off all of this cool 3D power that is WebGL. To do that, I’m going to implement the animate() function.

To start with I’m going to make a small change to the init function. I’m going to move the declaration of the mesh variable outside of the init() function so I can reference it in the animate() function. I’m also going to make a call to the animate() function just below my initial call to the init() function. The top of the application should now look like this:

var camera;
var scene;
var renderer;
var mesh;

init();
animate();

In the animate() function I’m going to add the following four lines of code:

mesh.rotation.x += .05;
mesh.rotation.y += .05;
render();
requestAnimationFrame( animate );

The first two lines of code are going to change the rotation of the cube along its x axis and its y axis. The third line of code is going to tell Three.js to render those changes to the screen. Finally, I’m going to schedule another call to the animate function.

Our animate() function should now look like this:

function animate() {
mesh.rotation.x += .05;
mesh.rotation.y += .05;

render();
requestAnimationFrame( animate );
}

Now if you reload the application, you will see the cube spinning in midair.

As you can see, creating a basic Three.js scene and animating it doesn’t take a lot of code.

You can check out two other demonstrations I have created. Each of these is an extension of our simple cube demonstration. And each allows you to fly through the scene using the w,a,s,d keys and by clicking and dragging the mouse to look around. Check out the Fly Through Demo and the Wave Demo using a Chrome browser.

Be sure to check out Part 2 here: WebGL and Three.js: Texture Mapping.

 

Image courtesy of Unsplash.