Lights, camera, object! Three.js part 1
For the last few weeks I’ve been trying to teach myself how do 3D on the web. I’ve been following Eric Hanes’ excellent course ‘Interactive 3D graphics’ on Udacity and trying to acquaint myself with the javascript library Three.js.
I’m going to attempt to talk you through how to build a spinning box example box like the one below. I’ll be basically rephrasing the Creating a scene walk through in the Three.js documentation with a few tweeks just to try and work out how much I’ve understood so far.
See the Pen Think inside the box by chris-creditdesign (@chris-creditdesign) on CodePen
To build this charming animation we first need to create three things. A scene, a camera and a renderer.
The scene of the crime
You place into the scene everything that you want to be part of your animation. In the 3D world that means lights, cameras and objects although we won’t worry about lights in this example. We create the scene here with:
var scene = new THREE.Scene();
The camera never lies
Next we’ll need to set up a camera. There are a number of cameras offered by Three.js but the most common one you’ll come across is the PerspectiveCamera
. It takes a few different attributes. The first is the field of view and the second is the aspect ratio. Aspect ratio is normally set to the total width of your animation divided by the height in order to get a properly proportioned output.
The next two attributes are the near and far clipping planes. Objects that are further away than the value of the far or closer than the near won’t be rendered. This won’t have much effect in this animation but in more complex examples it can aid performance by limiting the number of things the computer has to worry about all at once. We create the camera with:
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
The renderer
This is where Three.js takes all of you instructions and transforms them into WebGL so that they can be displayed on the screen. As well as the WebGL renderer Three.js also comes with some other rendering possibilities, such as canvas for older browsers/iPads etc.. But WebGL has by far the best performance so we’ll use that here.
Setting up the renderer is a three stage process. First we create an instance of the WebGL renderer. Then we set it to be the same size as our animation, in this case the size of the containing window. Finally we add the renderer’s domElement to the document body.
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
Geometries and materials
Now we’ve created a scene so it’s time to fill it with something to look at. Within the 3D graphics world things that we see on screen consist of two parts, a geometry and a material. The geometry is the shape of an object and the material is the colour or texture that is wrapped around it so that it can be seen.
Geometries consist of points (vertices) and fills (faces), basically a collection of triangles that combine together to build a shape. They can get very complicated very quickly. Once again Three.js comes to the rescue here with a bunch of pre-built geometries or shapes which we can just plug and play to get something on screen quickly. We’re going to use one of the most simple CubeGeometry
to build a box and pass into it three arguments, the cube’s width, height and depth.
var geometry = new THREE.CubeGeometry(2,2,2);
Alternatively, try this for some extra fun:
var geometry = new THREE.CubeGeometry((window.innerHeight*0.005),(window.innerHeight*0.005),(window.innerHeight*0.005));
Next we need to set up a material. Once again Three.js comes with a whole bunch of materials and we’re going to use one of the most simple ThreeBasicMaterial
as we don’t want to be worrying about lights and shadows and all that jazz right now. I’m going to set a colour for the material and then set wireframe
to true and wireframeLinewidth
to 10. This means that instead of applying the colour to the surfaces, just the edges of the shape will be coloured. Setting the wireframeLinewidth
to 10 gives us a nice fat line so that we can see it easily.
var material = new THREE.MeshBasicMaterial({color: "hotpink", wireframe: true, wireframeLinewidth: 10});
I chose hotpink
because it’s a well loved favourite. As well as named css colours you can also use regular hex colours prefixed with a zero and an x such as 0xFFFFFF
.
The mesh
The next piece of the puzzle is the mesh. In 3D land a mesh is used to mesh together a geometry and a material into a single object so that it can be rendered and viewed on our screen. That’s exactly what we’ll do here:
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
Everything is by default added to a scene right in the centre at the co-ordinates (0,0,0). So that we can have a chance of seeing what’s going on we’ll need to move our camera back a little. We do this by setting its z coordinate to 5 like so:
camera.position.z = 5;
The render loop
Despite of all our hard work we’re not actually rendering anything yet. To do that we’ll need to create a render loop.
var render = function () {
requestAnimationFrame(render);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
render();
This function creates a loop that tells the browser to redraw the scene 60 times a second (roughly every 16.66 milliseconds). The important parts to notice are renderer.render(scene, camera)
in which we tell the renderer to render the scene and the camera and requestAnimationFrame()
which is used to call the function over and over again. We could have used a plain old setInterval()
but requesting the animation frame has the advantage of stopping the animation if the user switches to another browser tab or application to hopefully prevent laptop meltdown. Finally cube.rotation.x += 0.01
and cube.rotation.y += 0.01
simply increase the cube’s x and y rotation values by a small amount each time the function is called to give a nice spinning animation.
I hope that all made sense. If not don’t blame me! I don’t know what the hell I’m talking about. Instead I’d highly recommend Eric Haines’ Udacity course as a great place to get started with Three.js and 3D graphics in general.
I’ll be writing more as I learn more so please keep in touch.