Three.js Basic Scene Tutorial

Gianluca Lomarco
10 min readDec 27, 2023

--

Three.js is a JavaScript library that enables the creation of three-dimensional environments on our web pages, offering unique interaction possibilities.

By seamlessly integrating 3D elements with standard HTML content such as titles, paragraphs, images, and buttons, it becomes possible to craft truly immersive experiences, heightening user engagement.

An illustrative example can be found in the multitude of websites earning daily accolades on platforms like Awwwards. The genres that derive the greatest benefit from these technologies are those centered around storytelling. However, this library can be applied in diverse ways on any website, extending to the creation of authentic video games. Further examples can be explored on the library’s own website:

This article shows how to start using three.js by creating our first 3D scene.

What do we need?

Let’s imagine we had to shoot a movie scene, what would we need?

First of all, we need a set, a place that contains all the elements of the scene like backgrounds, a series of elements to compose the setting to be recreated, etc. In addition to the scenography, there will be the actors who interact with each other and with the scene.

All of this will be caught by a camera, even more than one sometimes. But we couldn’t shoot anything if we didn’t have a set of well-positioned lights that illuminate everything.

Three.js allows us to create virtually all of this and render each frame taken by the camera inside an HTML element: the canvas. Three.js therefore does nothing more than generate the images of the individual frames of the scene which are then transferred to the canvas, and consequently to the web page.

But how does all this work?

Three.js uses javascript APIs called webGL, which allow us to communicate directly with the GPU of our computer and run two programs called SHADERS. Specifically, a Vertex shader and a Fragment shader.

Without going too technical, let’s just say that these two programs have the task of transforming the information contained in the geometries that make up the scene (the vertex shader) into a series of colored pixels that make up the frames (the fragment shader) which, in the end, end up in the canvas.

However, it must be specified that the shaders calculate only one pixel at a time and completely independently of each other. As a result, to generate a single frame at 1920x1080 (full HD) resolution, we have to run the shaders quite a few times.

Fortunately, the GPU takes care of these operations.

Unlike the CPU, which is made up of a few but very powerful processors, the GPU is made up of thousands of microprocessors and this allows it to perform many operations simultaneously. In this way, it can calculate thousands of pixels at the same time. Thanks to this calculation speed we can render even very complex scenes in real-time, reaching up to 60fps (60 frames per second).

The Book of Shaders — What is a fragment shader

Once this introduction is over, let’s move on to the code and create our project.

Project structure

For simplicity, we will not use a bundler manager, npm dependencies, or JavaScript modules. We will work with simple HTML files and a little JavaScript.

At the end of this article, you will find the link to the guide on how to create a basic scene with three.js using Vite.

Let’s then create an index.html file with the basic structure:

and an app.js file with a simple log:

Let’s import three.js

We have several possibilities to import the library into the project and we can find all these possibilities in the installation section of the documentation.

For now, we’ll just download the library files and link them to our index.html file using the <script> tag.

At this link, https://threejs.org/ simply click on download to download the zip file with the source code. Unzip the file and enter the build folder, copy the three.min.js file, and paste it into your project folder.

At this point we will need to attach the file to the end of the <body> tag like this, making sure to insert it before the app.js file as seen in the image.

At this point, inside the app.js file, we will have access to a variable called THREE which contains all the classes and utilities that we will soon use to create the project.

Let’s modify the app.js file to print this variable to the console and check that it exists.

Scene

We are ready to set the scene. The scene is our film set. It is nothing more than a container in which we will put the objects and the lights that we will film with a video camera.

To create the scene we just need to create an instance of the Scene class in this way.

Objects

Let’s create some objects to insert into the scene.

The objects are called Meshes and are always composed of two elements:

  • geometry
  • material

Broadly speaking we can say that geometry defines the shape of our objects while the material determines the final appearance (the color of the pixels). It’s a little more complex than that, but for now, it’s more than enough.

Let’s create a simple colored cube for now. We will use the BoxGeometry class for the cube geometry like this:

and then we create a material. Three.js provides us with many types of different materials, ready to use. To begin we will use the MeshBasicMaterial class to which we will pass a parameter containing the color of our cube like this:

We can specify the color in different ways, in this case, I used a number with hexadecimal notation, but we can pass a string very similarly to how we would in CSS, ‘#00ff00’ is always hexadecimal or even simply ‘green’. Three.js also provides us with a very useful Color class, especially if we need to do conversions of our color shades.

Now that we have the geometry and the material let’s create our Mesh and add it to the scene using the add(…) method:

Perspective Camera

The camera is the element that records everything that happens in the scene. The camera should not be inserted into the scene and therefore is not a visible element but identifies our point of view.

We can also have more than one camera, positioned at different points, and move from one to another as happens on a film set.

Three.js offers us mainly two types of cameras:

  • PerspectiveCamera (for perspective views)
  • OrthographicCamera (for axonometric views)

Today we will use the first to create our observation point. To create this type of room we need to pass two parameters.

Field of view

Corresponds to the width of the viewing angle. The larger this angle is, the more elements will enter the room, but they will be very distorted at the edges, as happens in a “wide-angle” view. The smaller it is, the less things will be captured by the camera and consequently very zoomed in as happens in a “telescopic” view.

Since it is an angle we will use a value of 75 degrees, a value which approximately corresponds to the visual field of our eyes.

The second parameter is the aspect ratio or the ratio between the width and height of the frame.

Aspect Ratio

In most cases, this value is the result of the division between the width of the canvas and its height. At this moment we don’t have this element yet, so temporarily we will use an object with generic height and width.

It is not necessary to add the camera to the scene, but if we wanted to add it it would not create any problems as it will not be visible anyway.

Let’s create the camera

The Renderer

The renderer is precisely the element that renders our scenes. Use the camera as a point of view and generate the frames that end up in the canvas.

By creating the renderer, the canvas will also be created which we must subsequently insert into the DOM inside the <body>.

With the setSize(…) method, we are setting the size of the frames that will be generated by the renderer and therefore also the size of the <canvas>, which we subsequently append to the <body>. To do this we use the same dimensions used to calculate the aspect ratio of the camera.

NB.

The camera aspect ratio must be identical to the canvas aspect ratio, otherwise the rendered images will be distorted. In the next chapters, we will see how to make our scene responsive.

We are almost finished, all we need to do is render our scene by invoking the render(…) method of the renderer to which we will pass two parameters: the scene to render and the camera to use as a point of view.

Once this is done we should see a completely black box on our page. Everything is working but there is a problem.

We have created the cube and the chamber, but we have not defined how they are positioned in space. Both have a position property that allows us to change the position in space by indicating the x, y, and z coordinates, as in a Cartesian plane.

By default the camera and objects are created at the center of the space, at the coordinates x = 0, y = 0, and z = 0. So our camera is located inside our cube. It will be enough to move it back a little to be able to see the cube correctly.

But in what direction should we move it?

Coordinates System (X, Y, Z)

The reference system of 3D space is composed of 3 axes X, Y, and Z.

Initially, the X axis is laid out horizontally and is oriented to the right, so positive values ​​will move our objects to the right, while negative values ​​will move them to the left.

The Y axis is arranged vertically and is oriented upwards. Consequently, positive values ​​will move objects up, and negative values ​​will move them down.

The Z axis is placed perpendicular to the monitor screen oriented towards the observer. By default the camera is oriented along the Z axis but in the opposite direction as shown in the figure.

So to move the camera backwards we must assign a positive value to the z coordinate.

Let’s reload the page to see a result like this:

The colored square in the center of the scene is our “green cube” that we are looking at from the front.

Conclusions

It’s certainly not the most exciting scene on the web, but it’s the first step, and it’s a necessary step because we’ve seen almost all the elements necessary for any 3D scene. In future articles, we will see better how to manipulate and animate objects. We’ll add some lights to the scene and replace the base material with something more realistic.

Below is the link to create the same scene with Vite.

And the lights?

You will have noticed that we have not put any lights, yet we are able to see the cube. How come?

This is due to the fact that the MeshBasicMaterial is not affected by light. By assigning a color to this material, that precise color will be applied to each pixel belonging to the geometry of the cube, without variations related to lighting.

This is in fact a somewhat particular material and is very convenient in very specific situations. In the vast majority of cases we need our materials to be influenced by the lights present in the scene, then we will use the other materials that three.js makes available to us.

Congratulations

For your first 3D scene made with three.js.

I invite you to change the position of the cube or camera by experimenting with different solutions to see how the image changes.

As you can imagine, in addition to the position we can also change the rotation and scale of our objects to obtain different results.

Also, feel free to add other objects to the scene by trying with other geometry like:

  • sphere
  • cylinder
  • cone
  • Torus

You can find them in the documentation.

You can also create different materials to bring Mesh to life with different geometries and colors.

--

--

Gianluca Lomarco

I am a creative developer working with webGL and fullstack Main teacher at Boolean Academy. Now I’am starting a new experience as content creator in YouTube