on webgl, Writings, Tutorials, ThreeJS

Get up to speed with three.js: setting your first scene

Introduction

If you imagine a film set, there's a guy pointing a camera at a scene of different props, and he can do so from different angles. It's all pretty similar in three.js, which is made up of objects that make coding 3D experiences much more natural to us. For example, three of the tools we have at our disposal when using three.js are below:

  1.  Scene - this contains all the 3D object data (all the props)
  2.  Camera - this has a field of view, position and rotation
  3.  Renderer - this figures out what objects look like from the camera's point of view

Three.js simplifies WebGL, enabling us to use simple concepts such as those above to produce 3D experiences with minimal code. The same would have required hundreds of lines of JavaScript when using WebGL directly.

In this tutorial, we'll be setting up the three.js environment in step 1, then using the Scene, Camera and Renderer objects listed above, getting an understanding of each in step 2. In the final step 3, we'll add an animating cube to the scene we've created.

The Outcome

Here's what we'll end up with - if you just want the code you can grab it from the codepen below or github. Otherwise, to learn about what's going on, continue reading from step 1.


Step 1: Download three.js & setup the HTML project

Download three.js

First, get a copy of three.js from its GitHub repository, and save it locally.

The reason I'm storing this locally is to prevent the applicaiton breaking if a different release of three.js is used. The latest version at the time of this tutorial was revision 71, so you should use r71 if you're having any issues. 

Apart from three.js, we're just going to be coding everything else within a single HTML file for simplicity.

Create the HTML project file

All we're doing below is including our local three.js library, and opening some script tags where most of the code will go.

<!doctype html>  
<html lang="en">
<head>
  <title>Three.js Tutorial</title>
  <meta charset="utf-8">
</head>
<body>

  <script src="three.js"></script>

  <script>

    //code will go here...

  </script>

</body>
</html>

Step 2: Create a Scene, Camera and Renderer

Camera man

Now, we'll declare 3 global variables, and assign each of them with a three.js object. First we'll create a Scene, then add a Camera, followed by the Renderer.

Create the Scene

The scene is really simple:

//declare scene variable  
var scene;

//create the scene
scene = new THREE.Scene();

Add the Camera

To add the camera, we assign a PerspectiveCamera object to a camera variable. There's a few different other camera options, but we'll use the PerspectiveCamera above:

//declare camera variable  
var camera;

//assign three.js perspective camera to variable
camera = new THREE.PerspectiveCamera(75, window.innerWidth/ window.innerHeight, 0.1, 1000);

Let's step through the arguments provided to the PerspectiveCamera:

  • The first argument we have provided, 75, is the field of view for the camera.
  • Second, window.innerWidth/ window.innerHeight is the aspect ratio.
  • The final two arguments are the clipping plane for far and near.

Add the Renderer

For rendering, we'll use the WebGLRenderer object, which will display our scene using WebGL. Alternatively, canvasRenderer() could have been used, which uses the canvas element - it's a good fallback for when WebGL is not available.

//declare renderer variable  
var renderer;

//assign WebGL renderer object
renderer = new THREE.WebGLRenderer();

//set the size of the renderer
renderer.setSize( window.innerWidth, window.innerHeight );

//add the renderer to the html document body element
document.body.appendChild( renderer.domElement );

Bring it all together

You can then combine all of the above code into something more manageable as seen in the snippet below. The variables are declared globally, and then we have an init() function, which we call at the bottom to build our scene.

    //Declare three.js variables  
    var camera, scene, renderer;

    //assign three.js objects to each variable
    function init(){

        //camera
        camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

        //scene
        scene = new THREE.Scene();

        //renderer
        renderer = new THREE.WebGLRenderer();
        //set the size of the renderer
        renderer.setSize( window.innerWidth, window.innerHeight );

        //add the renderer to the html document body
        document.body.appendChild( renderer.domElement );


    }

At this point, you still won't actually see anything if you run the code as there's nothing on the scene, and it isn't actually rendered. So let's fix that in the next step:


Step 3: Rendering a cube onto the scene

Cube

In this step, we'll first create a cube and add it to our scene, and then create a rendering loop which will run our scene.

Create the Cube

First, we declare the cube variable globally, so it can be used in other methods if necessary, then create the cube within an addCube function. To do this, we use BoxGeometry to create a geometry object, then create some material with a colour, and then Mesh them together to create to cube. After we add the cube to the scene, we have to set the camera position so that the cube becomes visible.

If that sounded complicated, it's actually really simple if you look at it line by line:

var cube;

function addCube(){

        //create box geometry object
        var geometry = new THREE.BoxGeometry( 1, 1, 1 );
        //create material with colour
        var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
        //combine geometry with material to create the cube
        cube = new THREE.Mesh( geometry, material );
        //add the cube to the scene
        scene.add( cube );

        //set the camera position
        camera.position.z = 5;
    }

Render the scene

Here, we define a render() function, which basically acts as a loop, firing 60 times a second:

    function render() {  
        //get the frame
        requestAnimationFrame( render );
        //render the scene
        renderer.render( scene, camera );
    }

Now to run all of this, just add the following to the bottom of your script:

    init();  
    addCube();
    render();

Animate the cube

To demonstrate how this render loop is actually working, we can animate the cube just by adding a couple lines within the render function:

    function render() {  
        //get the frame
        requestAnimationFrame( render );

        //animate the cube
        cube.rotation.x += 0.1;
        cube.rotation.y += 0.1;


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

Because the render function acts in a loop, it adds 0.1 to the x and y rotations of the cube 60 times a second, creating a rotating animation.


Well done

Good work, you've learned some of the very basics of three.js. I'll be adding a new tutorial to further manipulate the cube in the future.