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

Unlock content 🔓

To get access to 93 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 93 hours of video, a members-only Discord server and future updates, join us for only $95!

Next lesson

Procedural Terrain

Difficulty Hard

Introduction 00:00

In this lesson, we are going to transform a plane into a procedural terrain with mountains, water, beaches, plateaus, etc. using shaders:

We’ve already learned most of the techniques we are going to use and it’s an opportunity to practice while discovering a few more tricks.

Setup 01:04

The starter already contains the following:

  • A placeholder sphere with a MeshStandardMaterial applied to it
  • An HDR environment map for the background, which is also there to light up the scene
  • A DirectionalLight to light up the scene even more and cast shadows
  • The vite-plugin-glsl dependency to handle GLSL files
  • OrbitControls to rotate around
  • The three-custom-shader-material dependency to enhance built-in materials

Board 01:50

Instead of starting right away with the terrain, we are going to create the board around it. This board needs to look like this:

Although it looks quite simple, creating a hole in a plain geometry is actually rather difficult and there are many ways to do it, yet no simple one.

We could use the LatheGeometry with only 4 segments.

We could use ExtrudeGeometry.

We could create 4 BoxGeometry arranged in a specific way:

We could even create the model in a 3D software like Blender and import it.

All those solutions should get you the right result, but there is one more solution that I want you to discover and it’s the three-bvh-csg.

CSG stands for Constructive Solid Geometry, and BVH stands for Bounding Volume Hierarchy. Although very interesting, we are not going to explain those two topics.

To put it in a nutshell, three-bvh-csg enables boolean operations between geometries. As an example, you can use a sphere geometry to poke a hole in a box geometry.

In our case, we are going to start from box geometry, and then create a slightly smaller box geometry sticking out above and below. Then we are going to ask that last one to poke a hole in the first one:


three-bvh-csg is available on NPM: https://www.npmjs.com/package/three-bvh-csg

Install the library using npm install and force the version to 0.0.16:

npm install three-bvh-csg@0.0.16

We force the version to make sure it works with the lesson.


Each base shape that will be used in the operation is called a Brush.

Import Brush from 'three-bvh-csg':

import { Brush } from 'three-bvh-csg'

After the Placeholder section, add a Board section:

 * Placeholder
// ...

 * Board

We need two Brushes, one for the base shape and one to poke a hole in it.

To instantiate a Brush, we need to send it a Three.js geometry.

Let’s start with the base shape that we are going to name boardFill and instantiate a Brush using a BoxGeometry:

// Brushes
const boardFill = new Brush(new THREE.BoxGeometry(11, 2, 11))

We can’t see it, but the shape exists.

Next, let’s create the Brush that will poke a hole. Instantiate a new Brush using a BoxGeometry again, but change its size so that it’s tighter but higher. Finally, name it boardHole:

// Brushes
const boardFill = new Brush(new THREE.BoxGeometry(11, 2, 11))
const boardHole = new Brush(new THREE.BoxGeometry(10, 2.1, 10))


We have our two brushes; now, we want to poke a hole in boardFill using boardHole.

We need to instantiate an Evaluator.

Want to learn more?

That's the end of the free part 😔

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

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: