Going 3 Dimensional With Three.JS
Tags: javascript, 3d, threejs
Published: 2021-05-17 08:01:09

We've all wanted to create those cool websites with those amazing moving shapes which look 3 dimensional. The technology used for this is called WebGL. It's great and gives us a lot of freedom and flexibility. 


However, with this, comes a price. WebGL is complex and we need to write a lot of code for something as simple as a cube. Here's where [three.js] (http://threejs.org/) comes into play. [Three.js] (http://threejs.org/) adds a layer above WebGL while allowing almost the same amount of flexibility.

This is a the first post in a series of Three JS posts. Today, I'll show you how to create some basic shapes in three JS. 

We can use Three JS through NPM or by a CDN.

```
npm i three
```

We use the `canvas` element for our 3d figures. Canvas is used for drawing, it's in the name.

```
<canvas width="800" height="600" id="threejs-canvas"></canvas>
```

Let's select this canvas through javascript.

```javascript
const canvas = document.querySelector('#threejs-canvas');
```

###Scene
Firstly, let's begin by creating a `Scene`. A scene can be understood as the container for our 3d figures.


```javascript
import { Scene } from 'three';

const scene = new Scene();
```

###Parts of Objects
A basic object in Three JS has 3 fundamental parts:

#####Geometry
It is the shape/outline of an object. Now, we'll create a geometry of a cube.

```javascript
// Params are width & height
const geometry = new BoxGeometry(1, 1);
```


#####Material
It is the color/texture of the object. We can add unique looks and appearances by combining colors and textures. I'll create a detailed post on this very soon.

```javascript
const material = new MeshBasicMaterial({ color: 'cyan' });
```

We can use various color formats like `hexadecimal`, `rgb`, `hsl` etc.

###Mesh
It is used to combine the geometry and the material. We can also use it for rotations, scaling, transformations etc.

```javascript
const cube = new Mesh(geometry, material);
```

If you run the code, you'll see a black background but no cube. We may have created the cube but we have not added the cube to the scene.

```javascript
scene.add(cube);
```

After running that again, there's still no cube:

![Screenshot 2021-05-16 at 20.32.42](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/04fkmf2byafdoqk75ig3.png)
 
This is because we need to render our scene.

```javascript
const renderer = new WebGLRenderer({ canvas });

// Dimensions of the canvas
renderer.setSize(800, 600);
```

There are various renders but `WebGLRenderer` is what we need. Finally, we can see our cube:

![Screenshot 2021-05-16 at 20.36.40](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ubihpstulqij1h8sms6b.png)

###Controls
I think it be great if we could look around the cube i.e. view it from other angles. We can do this by changing the position of the camera. We could implement this on our own but three JS gives us a `class` we can use.

```javascript
const controls = new OrbitControls(camera, canvas);

// Adding easing for better UX
controls.enableDamping = true;
```

Now, let's try some other shapes:

###Sphere

```javascript
// The first argument is the radius
const geometry = new SphereGeometry(1);
const material = new MeshBasicMaterial({ color: 'cyan' });
const sphere = new Mesh(geometry, material);

scene.add(sphere);
```

If we run the code, we get something like this:

![Screenshot 2021-05-16 at 20.47.49](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1qgzjp4tg6bau25pf4fp.png)


As you can see, the edges are jagged. People who have used 3d software tools like blender, 3d max etc will know why this happens. This is because we lack detail on the sphere which is necessary for creating a smooth sphere. In fact, everything we create in three JS is made of triangles. So, we want to increase the number of triangles(or segments according to the docs). 

It's important that we don't go overboard with this because the amount the GPU has to compute is directly proportional to the number of segments. I'd recommend increasing the value slightly until most of the sharp edges disappear. The controls in most cases are used for debugging and the user will probably have a fixed camera angle.

```javascript
const geometry = new SphereGeometry(1, 32, 32);
const material = new MeshBasicMaterial({ color: 'cyan' });
const sphere = new Mesh(geometry, material);

scene.add(sphere);
```

Now, we get a nice and smooth sphere:

![Screenshot 2021-05-16 at 21.00.29](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fukut590ig5s9nhlxzp7.png)
 

###Torus
Most of the code is the same, we just need to change the class:

```javascript
// Params is the radius of the torus, radius of inner circle
const geometry = new TorusGeometry(1, 0.2);
const material = new MeshBasicMaterial({ color: 'cyan' });
const torus = new Mesh(geometry, material);

scene.add(torus);
```

If we execute the code, we can see that the torus is lacking some detail(same issue we had with the sphere). So, let's add some more segments to this.

![Screenshot 2021-05-16 at 22.25.40](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/47jmlly741cwtopykcmf.png)
 
```javascript
const geometry = new TorusGeometry(1, 0.2, 32, 32);
const material = new MeshBasicMaterial({ color: 'cyan' });
const torus = new Mesh(geometry, material);

scene.add(torus);
```

There, it looks much better:

![Screenshot 2021-05-16 at 22.30.41](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szyxiw6ulw4a67dl7j8z.png)



###Cone
```javascript
// Radius of bottom, height
// I've added segments to give it a smooth texture
const geometry = new ConeGeometry(1, 2);
const material = new MeshBasicMaterial({ color: 'cyan' });
const cone = new Mesh(geometry, material);

scene.add(cone);
```

Here's how it looks:
![Screenshot 2021-05-16 at 22.40.25](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x6f2bwfupoms77143ux3.png)

As you can see, we have the segment problem again. Let's fix that:

```javascript
const geometry = new ConeGeometry(1, 2, 32, 32);
const material = new MeshBasicMaterial({ color: 'cyan' });
const cone = new Mesh(geometry, material);

scene.add(cone);
```

And our nice looking cone:
![Screenshot 2021-05-16 at 22.41.44](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qexit8sc4ccws2mchiuk.png)

###TorusKnot
This is an interesting shape and I think it's cool and unique. 

```javascript
const geometry = new TorusKnotGeometry(1, 0.2, 128, 128);
const material = new MeshBasicMaterial({ color: 'cyan' });
const torusKnot = new Mesh(geometry, material);

scene.add(torusKnot);
```

![Screenshot 2021-05-16 at 22.45.38](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/579c6oqicfn27nfqr6ix.png)


There are many more geometries that are available [here] (https://threejs.org/docs/index.html?q=Geometry#manual/en/introduction/Creating-a-scene) in three JS.

###Debug Panels
These come real handy when we want to make little changes to test out colors, positions, angles etc. I like using [dat.gui] (https://www.npmjs.com/package/dat.gui) for this. Let's install it:

```
npm i dat.gui
```

Next, we need to initialize the GUI:

```javascript
import { GUI } from 'dat.gui';

const gui = new GUI(); 
```

Now we can see a panel at the top right:

![Screenshot 2021-05-16 at 23.00.09](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/euv5jrhgdype6qqn9mag.png)
 
We have a property called `wireframe` on our object. It removes the color/texture i.e. is the material and exposes the geometry(the outline of the object). 

```javascript
const geometry = new TorusGeometry(1, 0.2, 16, 16);
const material = new MeshBasicMaterial({});
const torus = new Mesh(geometry, material);

material.wireframe = true;

scene.add(torus);
```

Here's how it looks:

![Screenshot 2021-05-17 at 13.05.27](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g0mj0x854dml7ubjw2hl.png)

As you can see, there are a lot of criss-crossing lines. These are the segments(the triangles) of the shape.


Let's use this property in our debug GUI.

```javascript
gui.add(material, 'wireframe');
```

`gui.add()` takes in an object and `wireframe` is the property we want to toggle. The `gui.add()` method can take in various types of properties(the second argument which needs to be changed). We can use functions, booleans, numbers, ranges etc. One thing to note is that we have decided to change the `wireframe` property, if we specify something else(like `jdfkdfjkd` instead of `wireframe`), it won't work.

Here's how our GUI looks:
![Screenshot 2021-05-17 at 13.18.03](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p2zszmydwggftaa9nlud.png)

As you can see, the label for the property is the property itself(we gave the second argument as `wireframe` and that is also used as the label). 

```javascript
// Set the label to "Name1"
gui.add(material, 'wireframe').name('Name1');
```

After changing our label, here's how our GUI looks:
![Screenshot 2021-05-17 at 13.25.20](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4echixxra6q73a68z0oa.png)


###Conclusion
Three JS is super interesting and I think this could be the way to go in the future! Thanks for reading until here. Next,  I'll be writing about animating our figures by transformations, rotations etc. Bye for now 🤟