Shortcuts ⌨️

  • SPACE to play / pause
  • ARROW RIGHT or L to go forward
  • ARROW LEFT or J to go backward
  • ARROW UP to increase volume
  • ARROW DOWN to decrease volume
  • F to toggle fullscreen
  • M to toggle mute
  • 0 to 9 to go to the corresponding part of the video
  • SHIFT + , to decrease playback speed
  • SHIFT + . or ; to increase playback speed

⚠️ Update

If the the inset looks different than the one in the video, it might be because you changed the scale of the object.

  • Go in Object Mode
  • Press CTRL + A (MacOS and Windows) to open the Apply menu
  • Choose Scale

The object should look the same, but the scale will be reseted to 1 and the inset should work like in the video.

Unlock content 🔓

To get access to 72 hours of video, a members-only Discord server, subtitles, lesson resources, future updates and much more join us for only $95!

Want to learn more? 🖖


That's the end of the free part 😔

To get access to 72 hours of video, a members-only Discord server and future updates, join us for only $95!

Next lesson

Creating a scene in Blender

Difficulty Hard

Introduction 00:00

In this lesson, we will learn how to create a scene like the one on the home page of the Three.js Journey website. We are going to create a small landscape with a path leading to a magical portal with some objects along the way like fences, trees, rocks. When you are done, you will be able to use what you've learned to create rooms like the ones on Three.js Journey. Or anything else!

And, to make our scene look its best, we are going to use a technique called baking.

Baking 00:39

When you do a render in a 3D software like Blender, it usually looks better than the model you import into Three.js, no matter how hard you try to get the exact same lighting and colors. This is because of the technique used while making the render.

Ray Tracing consists of casting multiple rays toward each pixel of the render. These rays start with the geometry we are rendering. Next, they test the direction of each light in the scene to see which part of the geometry is illuminated as well as to test whether the directions of the light bouncing off the geometry are colliding with other objects in the scene. Then, for each of these collisions, more rays are being cast as they bounce off other objects. And it goes on and on like this multiple times. All of the information collected by these collisions is then computed to define the final color of that pixel.

The goal is to simulate real-life lighting and enable visual effects like indirect lighting and soft shadows. As an example, if you place a red object close to a white object, you'll see the white object being tinted with red because rays are bouncing from the red surface to the white surface. In the same way, you'll see that the red object looks brighter when the surface is close to the white object.

This process results in a beautiful realistic render, but doing one render can take many minutes, even hours.

When we are doing renders with WebGL, we need to do it as fast as possible in order to get a good frame rate. We don't have the luxury to spend minutes on just one render. For this reason, rendering in WebGL uses cheaper techniques that don't look as good but at least keep a decent frame rate.

The idea of baking is that we save those Ray Tracing renders into textures that we then use in WebGL instead of using the classic render techniques provided by Three.js.

Here is an example of baked texture:

And here is the result in Three.js:

There is no light, no real-time shadows. It's just the texture you see in the above example being placed on the geometries.

This way, we will see the Ray Tracing renders directly on the Meshes, and it looks awesome. And when we move around the scene, the performance will be great because all we did was to display a texture on a geometry.

Unfortunately, there are some drawbacks:

  • We have to bake everything in the 3D software and it's a long process.
  • We have to load the textures and if you have a complex scene with a lot of objects, you're going to need a lot of textures. This is bad for loading but it can also result in a short freeze at the beginning of the experience because we need to load those textures into the GPU.
  • The lights aren't dynamic. We can't move the lights, and we can't change their intensity or color in real time. We have to do it in the 3D software and re-bake everything.

Choosing to use baking or not is up to you and the project. Keep in mind that you can still mix baked and non-baked materials but it's hard to keep a homogeneous result.

Process 10:37

To create that baked scene, we need to go through multiple steps:

  • Create the scene in 3D software.
  • Optimize all the objects because we need clean geometries and only the surfaces we can see.
  • UV unwrap everything.
  • Bake the render into texture(s).
  • Export both the scene and the texture(s). If we do this, we are going to have just one big texture. But, we can have multiple textures if there are a lot of objects and we want better quality.
  • Import everything in Three.js and apply the texture on the mesh.

As a bonus, we will also add some details in Three.js to give more life to the scene like a cool portal effect with fireflies floating around.

Blender 12:52

We are going to use Blender to create our scene, bake it, and export it.

If you don't know Blender yet, you should follow the previous lesson dedicated to it. Assuming you now know the basics of Blender, the following steps are going to be a little more direct. Nevertheless, each part will be explained. Take your time and make sure to get everything right before moving forward.

If you are familiar with Blender and concepts like UV unwrapping, you can try to diverge from the lesson and create your own scene. If you're not familiar, you should try to follow the steps exactly. Then, once the project is over, you can try on your own and create your dream scene.

In this lesson, I'll be using the 2.92.0 version of Blender, but you'll probably use a more recent version. Keep an eye on potential changes in the interface or in the shortcuts.

Setup 14:44

To begin, we create a new Blender file. The default setup is the one we defined in the Blender lesson but you can use any setup you like. If you want the same setup, you can also use the portal.blend file in the starter:

A Point Light is already present in the scene with the following parameters.

If the parameters are different from yours, you might be using Eeevee as the Renderer Engine. You can change it now. We will be changing it anyway a little further down.

Start by deleting the default cube or any default object you have in the scene, but keep the light. Use X to delete objects.

You can now save the file. During the rest of the lesson, remember to save regularly.

Floor 17:24

We are going to start with the floor.

Create a simple plane with Shift + A

Scale that plane so that it covers 4 units. You can look at the grid on the floor of the scene to see what 4 units looks like. Also, those units can be anything you want. Actually, you might see something like 4m because your Blender is configured to use meters. This doesn't matter because 4 units in Blender will result in 4 units in Three.js.

To do that, you can change its size in the small menu that shows up when creating it:

You can also scale it using S after you've created it (you can use CTRL to round the value):

Or you can go to the Edit Mode with TAB and then scale it the same way:

The result will actually be slightly different according to which technique you used. If you scale the object while not using the Edit Mode, you'll apply a transformation on the object itself and not on the geometry.

This might become a problem later but, later on, we are going to fix it anyway for every object. So use the technique you prefer.

Fences 20:20

For the first objects in the scene, we can start with the fences. They are simple to create and will give some life to our scene.

We are going to create 2 flat boxes for the poles (posts) and 2 other flat and wide boxes for the planks (rails).

Create the first pole by making a cube with SHIFT + A. Go into Edit Mode with TAB and start scaling it:

If you don't get the exact shape at first, it's not a problem. You can always change it later.

Right now, we are in Edit Mode and we are going to stay in that mode for the rest of the fence. We can still create primitives and they will count as part of the same geometry. It's not mandatory but it might get handy to have only one geometry for each fence.

While in the Edit Mode, select the box (if that's not already the case) with A, duplicate it with SHIFT + D and move it to the side. You can press Y right after duplicating it to force the movement on the Y axis only:

Again, duplicate it with SHIFT + D, scale it with S and move it with G to create the two other planks:

Now that you have all the components of the fence, you can rearrange it any way you want. You can also center the whole geometry so that the origin (the small orange dot) is roughly at the bottom center of the fence:

Once you are happy with the result, leave the Edit Mode by pressing TAB:

You can now duplicate the fence to create 6 fences with SHIFT + D. Make sure you are in Object Mode and add some randomness to their position and rotation:

As always, don't spend too much time on positioning stuff. You can always do that later once you have all the objects.

Want to learn more?

That's the end of the free part 😔

To get access to 72 hours of video, a members-only Discord server and future updates, join us for only $95!

Next lesson

Baking and exporting the scene

How to use it 🤔

  • Download the Starter pack or Final project
  • Unzip it
  • Open your terminal and go to the unzip folder
  • Run npm install to install dependencies
    (if your terminal warns you about vulnerabilities, ignore it)
  • Run npm run dev to launch the local server
    (project should open on your default browser automatically)
  • Start coding
  • The JS is located in src/script.js
  • The HTML is located in src/index.html
  • The CSS is located in src/style.css

If you get stuck and need help, join the members-only Discord server: