Adventures in ThreeJS

I have done 3D graphics and all I did was open Blender and moved the default cube around. I couldn’t do anything to it. I don’t really understand 3D math, vectors and stuff confuse me. But something always makes me want to try it more and more! ThreeJS makes this super easy! It’s an open source library and has a lot of different methods to make 3D graphics through the browser super easy!

This post is me exploring the basics of ThreeJS. Parts of it may not be best practice and some of it is taken from various tutorials around the web. But most importantly, it is me finally understanding the very basics of 3D graphics.

Contents

Setting the scene

First things first, create a WebGL renderer. This creates a canvas element that is then appended into the DOM. Every time you want to re-render the scene, you need to call the .render method on this variable. It is also important to set the size to whatever you want, probably best to be the size of the container so you can then style that container element with CSS.

// Create a renderer
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
// Change size
renderer.setSize(container.offsetWidth, container.offsetHeight);
// Append canvas element to DOM
container.appendChild(renderer.domElement);

However, this doesn’t actually draw anything. There is no scene or even a camera to look through.

Scenes are where everything is rendered. All objects, lights and cameras are added to the scene. A camera is added to the scene so the user has something to actually look at. Without a camera, nothing would be visible. There isn’t just one camera either, there is a couple:

// Create scene
var scene = new THREE.Scene();
// Create camera
var camera = new THREE.PerspectiveCamera(45, container.offsetWidth / container.offsetHeight, 1, 4000);
camera.position.set(1.5, 1.5, 1.5);
scene.add(camera);

Now to the good bit - creating a 3D object! A 3D object is a mesh in its basic form. A mesh then consists of 2 different things:

// Create cube
var cube = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({
  color: 0xff0000
});
var mesh = new THREE.Mesh(cube, material);

Once the mesh is created, you add the mesh to the scene and then render the whole scene. Simple!

scene.add(mesh);

// Render
renderer.render(scene, camera);

Doing that you end up with a nice little box, like below. It doesn’t do anything, doesn’t move or flash. Its simply just a red cube.

Lighting the scene

In the scene we just created, there are no lights. So the box doesn’t really get shaded in anyway. There are a few different types of lights:

There are more than this, but these are the only ones I have really looked at. The docs list them all.

The below demo uses a DirectionalLight.

var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(1, .5, 2);
scene.add(directionalLight);

Animate it!

Whilst nice, it doesn’t really move or anything. That is where my favourite JavaScript function, requestAnimationFrame, comes in.

function run() {
  // Render
  renderer.render(scene, camera);

  // Change position
  var time = clock.getElapsedTime();

  mesh.rotation.z = Math.sin(time);

  requestAnimationFrame(run);
}

Add some more light

The below demo uses an AmbientLight just to add some light to rest of the scene - even though there is nothing else in the scene to light up.

Take over the world!

The final demo uses textures, bump maps and specular maps. This makes some cool mountain type effects on the earths surface. The bump map tells ThreeJS the height of each point, so rather than doing this manually, it’s done automatically through ThreeJS.

This is the bump map:

ThreeJS earth bump map

The specular map is telling ThreeJS what parts of the object are shiny and which aren’t. In this case, the water should be shiny and land should not be.

Both of these maps, including the original texture, are added to the material.

material.map = THREE.ImageUtils.loadTexture('images/earth.jpg');
material.bumpMap = THREE.ImageUtils.loadTexture('images/earth-bump.jpg');
material.bumpScale = .1;
material.specularMap = THREE.ImageUtils.loadTexture('images/spec.jpg');
material.specualColor = new THREE.Color('grey')

The End!

This is the end of my first full adventure with ThreeJS. I love the library and can see the endless possibilities. In fact, the homepage for ThreeJS shows just how powerful the library actually is.

I now can’t wait to getting some interaction into these. Movement with keys, physics and in the end, making a full game!

All the code for the examples above is on GitHub