00:00/00:00
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

⚠️ Update

If you get an error about the dependency tree unable to be resolved while trying to install postprocessing, add the --force parameter.

npm install --force postprocessing@6.35

⚠️ Update

Since we are using <ToneMapping>, there is a difference and you can see everything glowing.

You can fix that by setting the luminanceThreshold prop to 1.1:

<Bloom luminanceThreshold={ 1.1 } />

More about this attribute later.

⚠️ Update

You’ll notice references to an effect named SSR in the video and some leva controls associated with it.

As this effect is unstable, it has been removed from the lesson.

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? 👋

92%

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
63.

Post-processing

Difficulty Very hard

Introduction 00:00

Post-processing also benefits from the React and R3F system, as it has gotten easier to implement but is also optimized in some ways.

In this lesson, we are going to learn how it differs from the post-processing techniques we’ve covered before, implement a bunch of effects, and even create our own effects.

The issue with post-processing 01:11

In the previous lessons, we’ve used post-processing by adding passes.

Those passes had their own code and were completing one or multiple renders in order to achieve the desired result.

Then the next pass would do the same, and again, and again.

Those passes all occurred independently and some of them were doing the same renders (depth renders, normal renders, etc.), which resulted in performance issues and limited the number of passes we could add before getting a frame rate drop.

The solution 03:02

And this is exactly what Post Processing is trying to resolve.

The various passes will be merged into the least number of passes possible. In fact, we don’t talk about passes anymore, but we talk about “effects”.

Those effects will be merged together into one or multiple passes (if needed) automatically while keeping the order in which we added them.

We can even choose the blending of each effect (more about that later).

And, as you might’ve guessed, we can use Post Processing in R3F with @react-three/postprocessing.

Setup 04:27

In the starter, we have the classic orange sphere, purple cube, and green floor.

We also have a directional light source and an ambient light source.

The @react-three/drei dependency is already installed within the project and we are using the OrbitControls helper to be able to move the camera around.

We also have <Perf /> from r3f-perf in order to keep an eye on performance.

Implement 04:56

We need two dependencies, @react-three/postprocessing, and postprocessing.

But for now, the only one we need to install is @react-three/postprocessing since this dependency will also install postprocessing.

In the terminal, use npm install @react-three/postprocessing@2.16 (we force the versions to prevent surprises, you can ignore potential vulnerability warnings).

In Experience.jsx, import EffectComposer from @react-three/postprocessing:

import { EffectComposer } from '@react-three/postprocessing'

Although it’s the same name as the EffectComposer we used in native Three.js, it’s not the same class.

Now, add it to the JSX:

export default function Experience()
{
    return <>

        <EffectComposer>
        </EffectComposer>

        {/* ... */}

    </>
}

EffectComposer is now running, but the colors are now completely off.

This is due to the tone mapping being deactivated in the post-processing rendering process for more appropriate color management.

We can fix that by adding the tone mapping ourselves as an effect at the end of the <EffectComposer>.

Import ToneMapping from @react-three/postprocessing:

import { ToneMapping, EffectComposer } from '@react-three/postprocessing'

Then, add <ToneMapping> inside <EffectComposer>:

<EffectComposer>
    <ToneMapping />
</EffectComposer>

That’s better, but the picture looks gray-ish.

This is due to the default tone mapping applied by ToneMapping named AgX. AgX is a quite recent tone mapping which looks okay, but it’s not the default one used by R3F.

To change that, first we need to import the list from postprocessing. Yes, I’m talking about the original postprocessing library, not the React Three implementation.

Because we’ve added @react-three/postprocessing to the project, we can already import things from postprocessing directly, but it’s considered good practice to add it ourselves to the project so that we don’t have to rely on other dependencies.

In the terminal run npm install postprocessing@6.35 (we force the versions to prevent surprises, you can ignore potential vulnerability warnings).

If you get an error at this exact step, something about the dependency tree unable to be resolved, run npm install --force postprocessing@6.35 instead.

To get the list of blends, import available tone mappins from postprocessing, we need to import ToneMappingMode from postprocessing:

import { ToneMappingMode } from 'postprocessing'
console.log(ToneMappingMode)

The one we want is ACES_FILMIC and we can apply it to the <ToneMapping> using the mode prop:

<EffectComposer>
    <ToneMapping mode={ ToneMappingMode.ACES_FILMIC } />
</EffectComposer>

The color is back.

Remove the console.log(ToneMappingMode).

Note that we don’t even need to add the first render, since Post Processing will take care of that.

Be careful, in the following parts, as you might have to reload the page after tweaking or adding an effect.

Multisampling

We can assign various attributes to the <EffectComposer>, but the most interesting one is multisample.

As discussed in the previous lessons, multi-sampling is used to prevent the aliasing effect (the little stairs on the edges of geometries).

By default, its value is at 8 and we can lower it down to 0 in order to disable it completely.

<EffectComposer multisampling={ 0 }>
    <ToneMapping mode={ ToneMappingMode.ACES_FILMIC } />
</EffectComposer>

(Note that you will probably not see a big difference in the screenshot above because of the image compression)

Performance should be better when disabling multi-sampling, but we don’t really care about that in this lesson, so let’s remove it and keep the default value:

<EffectComposer>
    <ToneMapping mode={ ToneMappingMode.ACES_FILMIC } />
</EffectComposer>

Finding effects and how to implement them 16:17

In the following part of the lesson, we are going to test a bunch of effects for the sake of learning.

We are going to set very specific values without going too much into detail because it would take ages and be boring.

But you should roam the documentation in order to discover the various effects, test them, and see how they work.

Unfortunately, the documentation (though useful) is a bit messy and spread across react-postprocessing and Post Processing, which means you’ll have to dig a little in order to find what you are looking for.

Here are the links that you might need.

Post Processing:

React-postprocessing:

Vignette effect 21:10

Let’s start with a very common effect, the Vignette effect.

Vignette will make the corners of the render a little darker.

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:

Discord