Three.js Hello Cube - A Beginner's Guide
Tags: threejs, webgl, 3d, javascript
Published: 2021-08-08 03:33:25

Imagine you are Hollywood's best director and you are ready to shoot the greatest scene. You are standing in front of an empty set. What do you think you'll need?

A movie scene is very similar to a Three.js scene. We will create a Hello Cube and figure out the basics of Three.js. 

While we can have an extensive list of things to add to our movie set, three things will be impossible to do without. The first is our movie star. Second, we will need a camera to capture our scene. Lastly, we will need a screen to view what we just captured.

Briefly, Three.js is a JavaScript library and Application Programming Interface (API) first released by Ricardo Cabello in April 2010. Since release, Three.js has grown to a robust library with thousands of contributors. Three.js uses WebGL to enable easy creation of 3D content. WebGL is a low-level cross-platform API that creates simple shapes such as points, lines and triangles. Because WebGL is low-level, we would need a lot of code to even draw a single triangle. Three.js makes this task much easier.

In Three.js, our object will be represented by a something called a Mesh. A "mesh" is a 3D form created using vertices. Each vertex is represented by a X, Y and Z dimension coordinate planes. X is the horizontal plane or the left to right plane. Y is the vertical plane or the top to bottom plane. Z is the depth plane or the front to back plane. 

If we have three vertices, we can draw a straight line connecting one vertex to another to form a triangle. This is the simplest shape we can create in WebGL. If we wanted to create a flat rectangle we would need at least two triangles (at least 4 vertices). By adding multiple vertices we can create very complex shapes even the smoothest of spheres.

That's enough talk. Let's write some code. We can separate the files but to make this even more simple, we will use a single HTML file. Our goal is to make a 3D cube. 

```html
<html>
<head>
    <title>Your First Three.js Scene</title>
    <style>
        *{
            margin: 0;
        }
        .display{
            position: absolute;
            top: 0;
            left: 0;
            outline: none;
        }
        html, body{
            overflow: hidden;
        }
    </style>
    <script type="module">
        import * as THREE from "https://cdn.skypack.dev/pin/three@v0.131.3-QQa34rwf1xM5cawaQLl8/mode=imports/optimized/three.js"
    </script>
</head>
<body>
    <canvas class="display"></canvas>
</body>
</html>
```
We created a `<canvas>` element. Going back to our analogy, the `<canvas>` element could be thought of as our screen to display our captured scene. Everything from our scene will be displayed or rendered inside this `<canvas>` element. We then set our basic CSS to hide overflow, remove any margin and give an absolute position to our canvas. We then imported the Three.js module into our `<script>`.

We will write the remaining code inside the `<script>` element.

Now we are ready to instantiate our `<canvas>` inside our script. We can do that using `document.querySelector()`.
```javascript
//instantiate canvas
const canvas = document.querySelector('.display')
```
We used the `<canvas>` element class to link it to our scene. Just like that, we are ready to create our scene. In our scene, we will add a cube mesh. Continuing with our analogy, the cube is the star of our scene. Like all great movie scenes, we need to be specific about our cast. We have to provide two requirements to make our cube mesh. The first is a geometry and the second is a type of material. 

Three.js makes it very easy for us. Because, shapes such as: box, sphere, cone, circle, plane and many more geometries are already provided in the library. Different geometries require different inputs. A box geometry requires a width, height and depth float values.

We can also choose from several materials but for now we will go with a Mesh Basic Material. We have an option of adding a color to our material so we will make it Cyan. After we select our parameters we will add the cube to our scene. 

```javascript
//create a scene
const scene = new THREE.Scene()

//create a cube
const cube = new THREE.Mesh(
    //box geometry with a width, height and depth
    new THREE.BoxGeometry(1, 1, 1),

    //apply a mesh basic material to our mesh
    new THREE.MeshBasicMaterial ({
      color: 0x00ffff 
    })
)
//add our mesh to the scene
scene.add(cube)
``` 

We have completed one of the three necessary requirements to make our scene. We still need to make our camera and our renderer. Our camera will capture our scene and the renderer will display our scene on our canvas. 

Three.js gives us several options for a camera but for now we will go with a Perspective Camera. A perspective camera displays objects closer to the camera as larger and objects further away as smaller. This could simply be represented by a shape called a frustum. A frustum is a cone or pyramidal shaped object with the pointy-end cutoff. The perspective camera displays objects in a way that a cube would look like a frustum. The perspective camera needs four inputs. These are: field of view (FOV), aspect ratio of the display, near value and far value. The FOV is the angle measure from bottom to top given as a float value. The aspect ratio is the canvas width divided by the canvas height. The near and far values are the depth field we want the camera to capture.

```javascript
//create camera
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 100)
scene.add(camera)
camera.position.z = 3
``` 

Note that the camera position like any object is represented by an x, y and z values with in the scene. By default the object and the camera are both placed at 0, 0, 0. To capture the object we need the camera to be in front of the object. If our monitor had a box shape, the positive z value points towards you and the negative z value points towards the back of the monitor. 

One last thing we need to do is to add the renderer. Three.js provides us with several renderer options but for now we will go with WebGLRenderer. We will display our captured scene using the renderer in our canvas. The renderer has a `.render` method that requires the scene we want to render and the camera we used to capture this scene. 

```javascript
//create renderer
const renderer = new THREE.WebGLRenderer({canvas})
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.render(scene, camera)
```
 
Look at that! You created your first Hello Cube!

From this view, our cube appears to be just a square. But we are going to work some camera magic and make it rotate. We will do this using Orbit Controls. Orbit control rotates the camera around a given target. In this case, the center of the scene, where our cube is placed. First we will load orbit controls. 

```javascript
import { OrbitControls } from "https://cdn.skypack.dev/three@v0.131.3-QQa34rwf1xM5cawaQLl8/examples/jsm/controls/OrbitControls.js"
``` 

And then instantiate it. Orbit control requires the camera and the canvas it will animate on. We will enable a damping of the camera movement that will prevent jerking camera movement. we will also make it auto rotate. 

```javascript
//instantiate OrbitControls after camera and canvas
const controls = new OrbitControls(camera, canvas);

//smooth rotation of camera
controls.enableDamping = true;

//auto rotation of camera
controls.autoRotate = true;
```

In order to constantly update the scene we need to create a function that will call `window.requestAnimationFrame()` that calls the function itself continuously. The number of callbacks is usually 60 times per second.

```javascript
//create a call back function
const updater = () => {
    //call the same function again
    window.requestAnimationFrame(updater)

    //update the orbit controls with every function call
    controls.update()

    //render the scene again with every function call
    renderer.render(scene, camera)
}

//call the function
updater()
``` 

Now we can move the camera with in our canvas using our mouse. 

From here, the possibilities are endless. Three.js gives developers the ability to utilize WebGL to create responsive, interactive and engaging web content. There are many resources available to read and learn more about Three.js.

https://threejs.org/
https://threejs-journey.xyz/
https://threejsfundamentals.org/

Thank you for your time. I hope this post was helpful to you. 

You can find me on at https://twitter.com/nate_dev_