00:00/00:00TIME LEFT
Choosing the a bcd
3:22
00:03:22

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

Want to learn more? 🤘

34%

That's the end of the free part 😔

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

Next lesson
25.

Realistic render

Difficulty Hard

Downloads
Starter packFinal project

Introduction 00:00

When we imported our hamburger in the previous lesson, the colors were off. To put it in a nutshell: many things participate in a wrong looking model.

Sometimes, we want a very realistic render. Maybe it's because we want to showcase a real-life product on our website. Or perhaps we are 3D artists, and we want to show off our work with the best possible result. Anyway, we need a render as real as possible.

In this lesson, we will learn many techniques to improve our model looks once rendered in Three.js. Be careful though, some of those techniques can have a performance impact, and some techniques depend on your model. You'll have to adapt according to the situation.

Setup 01:04

We could use our hamburger, but it's better to try a more realistic model with textures, normal maps, etc. We will use the Flight Helmet from the GLTF Sample Models repository. You can find the model in the /static/models/ folder.

This lesson is also the perfect opportunity to revise what we already learned. That is why there isn't much code in the starter. We will have to instantiate the loaders, the lights, the shadows, etc., all by ourselves.

We will also use Dat.GUI to tweak as many parameters as possible. That is required if we want to create the perfect environment.

For now, all we have in our scene is a white sphere and an instance of Dat.GUI.

This sphere is just a placeholder to make sure that the starter is working, but we can use it to set up the lights. Change the material of testSphere to MeshStandardMaterial to see the lights we are about to add:

const testSphere = new THREE.Mesh(
    new THREE.SphereGeometry(1, 32, 32),
    new THREE.MeshStandardMaterial()
)

As you can see, everything has gone black.

Lights 02:18

We are going to use only one DirectionalLight. But how can we have a realistic render with only one light? The environment map will do most of the heavy leverage and simulate light bounce. We could get rid of any light, but the DirectionalLight is important if we want to have more control over the lighting but also to create shadows:

const directionalLight = new THREE.DirectionalLight('#ffffff', 1)
directionalLight.position.set(0.25, 3, - 2.25)
scene.add(directionalLight)

Let's add some parameters to our Dat.GUI:

gui.add(directionalLight, 'intensity').min(0).max(10).step(0.001).name('lightIntensity')
gui.add(directionalLight.position, 'x').min(- 5).max(5).step(0.001).name('lightX')
gui.add(directionalLight.position, 'y').min(- 5).max(5).step(0.001).name('lightY')
gui.add(directionalLight.position, 'z').min(- 5).max(5).step(0.001).name('lightZ')

We can now control the position and intensity.

Default Three.js light intensity values aren't realistic. They are based on an arbitrary scale unit and don't reflect real-world values. You could say it doesn't matter, but it's better to base our scene on realistic and standard values. It might be more comfortable to reproduce real-life conditions that way.

To change Three.js lights for more realistic values, switch the physicallyCorrectLights property of the WebGLRenderer instance (the renderer) to true:

renderer.physicallyCorrectLights = true

Our light appears dimmed. Let's increase its intensity to 3:

const directionalLight = new THREE.DirectionalLight('#ffffff', 3)

Model 08:31

Let's load our model instead of that test sphere.

First, instantiate the GLTFLoader. We will regroup the different loaders together. There is no particular reason for that but to regroup things together:

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'

// ...

/**
 * Loaders
 */
const gltfLoader = new GLTFLoader()

We don't need the DRACOLoader because the model isn't compressed. But if you load a Draco compressed model, instantiate the DRACOLoader as we did in a previous lesson.

We can now load our model located in /static/models/FlightHelmet/glTF/FlightHelmet.gltf:

/**
 * Models
 */
gltfLoader.load(
    '/models/FlightHelmet/glTF/FlightHelmet.gltf',
    (gltf) =>
    {
        console.log('success')
        console.log(gltf)
    }
)

As always, go slow, make sure that the model is well loaded with no error, and study the imported result.

Because it's a complex model, we will simply add the gltf.scene group to our own scene:

gltfLoader.load(
    '/models/FlightHelmet/glTF/FlightHelmet.gltf',
    (gltf) =>
    {
        scene.add(gltf.scene)
    }
)

If you can't see it but don't get any error, Remove your testSphere and zoom a little. The explanation is simple: the loaded model is too small.

Increase its scale, move it down a little, and rotate it so it fits our camera view better:

gltfLoader.load(
    '/models/FlightHelmet/glTF/FlightHelmet.gltf',
    (gltf) =>
    {
        gltf.scene.scale.set(10, 10, 10)
        gltf.scene.position.set(0, - 4, 0)
        gltf.scene.rotation.y = Math.PI * 0.5
        scene.add(gltf.scene)
    }
)

Let's also add a tweak to rotate the whole model in our Dat.GUI:

gltfLoader.load(
    '/models/FlightHelmet/glTF/FlightHelmet.gltf',
    (gltf) =>
    {
        // ...

        gui.add(gltf.scene.rotation, 'y').min(- Math.PI).max(Math.PI).step(0.001).name('rotation')
    }
)

Want to learn more?

That's the end of the free part 😔

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

Next lesson

Code structuring for bigger projects

How to use it 🤔

  • Download the Starter pack or Final project
    (if your browser detects a menace, do not worry, it is not)
  • Unzip it
  • Open your terminal and go to the unzip folder
  • Run npm install to install dependencies
    (if your terminal warn you about vulnerabilities, ignore it)
  • Run npm run dev to launch the local server
    (your browser should start 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:

Discord