TECH3

BEYOND THE RENDER​​

08                                        2025-2026

In dit onderdeel zien we hoe we postprocessing in React Three Fiber gebruiken. We leren hoe we leuke effecten kunnen integreren zonder veel performantie te verliezen. Dit allemaal dankzij EffectComposer

BEYOND THE RENDER

EFFECTCOMPOSER

01

01

EFFECTCOMPOSER

WHAT IS IT?

Post-processing is het toepassen van visuele effecten op een 3D-scene  het renderen, om het beeld mooier, filmischer of realistischer te maken.

In React Three Fiber kun je dit ook doen. Daarvoor heb je een onderdeel nodig dat we nog niet eerder gebruikten: ‘postprocessing’. Installeer het met het commando hieronder.

npm install @react-three/postprocessing

01

EFFECTCOMPOSER

IMPLEMENT

In 'postprocessing' hebben we een component genaamd 'EffectComposer' die ons in staat zal stellen om verschillende effecten toe te voegen aan onze scene.

Importeer EffectComposer en plaats deze in je Experience.

export default function Experience()
{
    return <>

        <EffectComposer>
        </EffectComposer>

        {/* ... */}

    </>
}

Kijk eens naar je scene... De kleuren zijn nogal raar.

01

EFFECTCOMPOSER

TONEMAPPING

Dit komt omdat tonemapping gedeactiveerd wordt in het post-processing process (om betere kleurmanagement te hebben). We kunnen dit terug goed krijgen door de tonemapping als een effect toe te voegen.

Importeer ToneMapping en Plaats dit tussen EffectComposer.

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

<EffectComposer>
    <ToneMapping />
</EffectComposer>

We kijken opnieuw naar onze scene en nu zijn onze kleuren 'washed out'... Sigh!

01

EFFECTCOMPOSER

DEFAULT TONE

De reden hiervoor is dat AgX tonemapping als default wordt gebruikt. Om dit te veranderen moeten we eerst postprocessing installeren. Dit is niet van react three fiber.

Installeer 'postprocessing' door volgende commando

npm install postprocessing

We zien een heleboel Tonemaps. Je zou dit in een Leva kunnen plaatsen en zien wat alles doet

We importeren nu ToneMappingMode van 'postprocessing' en loggen deze eerst.

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

01

EFFECTCOMPOSER

ACES FILMIC

Wat wij willen is de ACES_FILMIC tonemap want deze leunt het dichtst aan bij wat we gewoon zijn.

Gebruik de ACES_FILMIC ToneMappingMode op onze ToneMapping effect door het attribuut 'mode'.

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

Ons kleur is terug zoals we het willen en gewoon zijn.

01

EFFECTCOMPOSER

MULTISAMPLING

Er zijn verschillende attributen op EffectComposer mogelijk maar degene waar wij in geinteresseerd zijn is 'multisample'. Deze zal voorkomen dat we een aliasing effect krijgen (stairs effect). By Default is deze waarde 8

Plaats de multisampling op 0 en kijk naar het verschil

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

Hoe lager onze multisampling, hoe beter onze performance zal zijn. Afhankelijk van je effecten zul je dit moeten aanpassen indien je vertraging ziet.

BEYOND THE RENDER

EFFECTS

02

02

EFFECTS

WHERE? WHAT? HOW?

We gaan nu een paar effecten bekijken en ermee spelen. Er bestaan er superveel, met nog meer instellingen. Alles één voor één afgaan is… nogal saai, dus we pikken gewoon een paar leuke eruit.

Wil je meer weten over effecten en welke er zijn? Bekijk de documentatie.

02

EFFECTS

VIGNETTE

We starten met het meest standaard effect, het Vignette effect.
Dit zal de hoeken van de canvas wat donkerder maken.

Importeer Vignette en plaats deze tussen EffectComposer.

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

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

Maak dat Tonemapping als laatste element tussen je EffectComposer zit. Het idee is dat al onze effecten uitgevoerd worden en dan pas de kleuren juist gezet worden om een accurater resultaat te krijgen.

02

EFFECTS

VIGNETTE

Zie je het vignette niet zo goed? Deze kan je altijd nog aanpassen door de verschillende options die we kunnen meegeven.

Plaats een offset en darkness attribuut op de Vignette met waarden naar keuze.

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

<EffectComposer>
    <Vignette
    offset={ 0.3 }
    darkness={ 0.9 }
	/>
    <ToneMapping mode={ ToneMappingMode.ACES_FILMIC } />
</EffectComposer>

02

EFFECTS

BLENDING

We kunnen een BlendFunction meegeven aan vignette alsook aan andere effecten. Vergelijk dit een beetje met photoshop waar je verschillende blend modes hebt. Deze moet je wel importeren uit postprocessing.

Importeer BlendFunction en log deze om te zien wat erin zit.

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

Zet nu de blendFunction op COLOR_BURN op de vignette en kijk naar het resultaat.

<Vignette
    offset={ 0.3 }
    darkness={ 0.9 }
    blendFunction={ BlendFunction.COLOR_BURN }
/>

Zet nu maar terug op NORMAL want dat was niet ... mooi.

02

EFFECTS

BACKGROUND

Misschien viel het je op maar de Vignette werkt niet op de achtergrond.
Dit komt omdat de render transparant is by default. We kunnen dit fixen door kleur toe te voegen zoals eerder gezien. 

Voeg een color toe op volgende manier.

export default function Experience()
{
    return <>

        <color args={ [ '#ffffff' ] } attach="background" />

        {/* ... */}

		<>
}

02

EFFECTS

GLITCH

Naast Vignette hebben we ook een glitch effect. Bruikbaar? Misschien niet altijd maar wel cool. We zullen deze eens testen.

Importeer Glitch , comment de Vignette en voeg Glitch toe aan de EffectComposer.

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

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

We kunnen ook spelen met de attributen.

<Glitch
    delay={ [ 0.5, 1 ] }
    duration={ [ 0.1, 0.3 ] }
    strength={ [ 0.2, 0.4 ] }
/>

02

EFFECTS

GLITCH

Ook bij glitch hebben we een mode en deze aanvaard GlitchModes van postprocessing. Dit zijn presets van snelheden en hoeveelheden.

Importeer GlitchMode en log deze naar de console.

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

Voeg nu CONSTANT_MILD toe aan de mode van Glitch

<Glitch
    delay={ [ 0.5, 1 ] }
    duration={ [ 0.1, 0.3 ] }
    strength={ [ 0.2, 0.4 ] }
    mode={ GlitchMode.CONSTANT_MILD }
/>

BEYOND THE RENDER

EFFECTS (PART 2)

03

03

EFFECTS (PART 2)

NOISE

We gaan het Noise effect onderzoeken. Dit zal een 'sneeuw' effect geven zoals op de oude televisies. 

Importeer Noise van postprocessing en comment het Glitch effect.

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

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

Ook Noise heeft een mogelijkheid tot blendFunction. Zet deze op SOFT_LIGHT.

<Noise
    premultiply
    blendFunction={ BlendFunction.SOFT_LIGHT }
/>

Je kan ook de premultiply die eerst zal multiplyen en nadien blenden.

03

EFFECTS (PART 2)

BLOOM

Nu het meest coole effect en hetgeen wat je waarschijnlijk veel zal kunnen gebruiken (in donkere scene's toch). Hiervoor gaan we eerst onze scene donker maken.

Verander de kleur van de achtergrond naar zwart om beter het effect te zien.

<color args={ [ '#000000' ] } attach="background" />

Importeer Bloom, voeg die aan EffectComposer toe en comment het Noise effect.

import { Bloom, Noise, Glitch, Vignette, ToneMapping, EffectComposer } from '@react-three/postprocessing'

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

03

EFFECTS (PART 2)

BLOOM

Default waarden van Bloom maakt dingen nogal te rap 'glowy'. We kunnen dit fixen door de threshold omhoog te plaatsen op luminanceThreshold.

Verander de threshold naar 1.1 op de Bloom.

<Bloom luminanceThreshold={ 1.1 } />

Nu moeten we een manier vinden om de kleuren te pushen voorbij hun boundaries. Dit deden we al eens eerder door een array mee te geven. Verander de kleur op de material naar volgende.

<meshStandardMaterial color={ [ 1.5, 1, 4 ] } />

Een beetje teleurstellend? We hadden een serieuze glow verwacht... dit kan ook door het mipmapBlur attribuut toe te voegen aan onze Bloom.

<Bloom luminanceThreshold={ 1.1 } mipmapBlur />

03

EFFECTS (PART 2)

COLOR

Nu kan je makkelijk met de kleurwaarden spelen.

Verander de kleur eens naar rood.

<meshStandardMaterial color={ [ 4, 1, 2 ] } />

Of naar Oranje

<meshStandardMaterial color={ [ 5, 2, 1 ] } />

Een andere manier om dit te implementeren is door een color mee te geven alsook een emmisive property en de intensity omhoog te plaatsen.

<meshStandardMaterial color="orange" emissive="orange" emissiveIntensity={ 2 } />

Wil je een feller kleur in het midden? Zet je oorspronkelijk kleur gewoon op wit.

<meshStandardMaterial color="#ffffff" emissive="orange" emissiveIntensity={ 2 } />

03

EFFECTS (PART 2)

UNIFORM COLOR

Indien je een uniform kleur wilt in je bloom dan kan je het materiaal veranderen naar een meshBasicMaterial maar dan kan je geen gebruik maken van de emmisive en emmisiveIntensity methode.

<mesh castShadow position-x={ 2 } scale={ 1.5 }>
    <boxGeometry />
    <meshBasicMaterial color={ [ 1.5, 1, 4 ] } />
</mesh>
<Bloom
    mipmapBlur
    intensity={ 0.5 }
    luminanceThreshold={ 0 }
/>

Je kan ook de intensiteit controleren op de Bloom zelf (default staat deze op 1) en de luminanceThreshold.

03

EFFECTS (PART 2)

UNIFORM COLOR

Nu heeft alles een glow. Je kan dus spelen met die waarden en zo een heel mooi Bloom effect krijgen. Dit is 1 van de coolste effecten (zeker op bv. een lantaarnpaal) die er zijn maar overdrijf hier niet in. Dit kan snel afleidend/storend.

<color args={ [ '#ffffff' ] } attach="background" />

We zetten onze background color terug op wit of doen deze weg.

03

EFFECTS (PART 2)

DEPTH OF FIELD

Een laatste leuk effect is de Depth of Field. Net zoals een camera kunnen we onze objecten onscherp/scherp stellen. Een object die verder staat zal blurry zijn en een object die dichter staat is scherp.

import { DepthOfField, Bloom, Noise, Glitch, ToneMapping, Vignette, EffectComposer } from '@react-three/postprocessing'

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

Importeer DepthOfField en plaats deze tussen onze EffectComposer. Comment onze Bloom.

03

EFFECTS (PART 2)

DEPTH OF FIELD

Out-of-the-box is het al goed maar we kunnen dit zelf aanpassen door bepaalde attributen.

<DepthOfField
    focusDistance={ 0.025 }
    focalLength={ 0.025 }
    bokehScale={ 6 }
/>
  • focusDistance: Welke afstand zal het scherp zijn.
  • focalLength: De afstand van de focusDistance vooraleer het maximum blurt.
  • bokehScale: De Blur Radius

Deze waarden zijn in normalized space (van 0 tot 1) gekoppeld aan de near en far van de camera. Je zal dus wat moeten zoeken en tweaken vooraleer je het perfecte resultaat vindt.

BEYOND THE RENDER

PERFORMANCE

04

04

PERFORMANCE

PERFORMANCE

We kunnen nu alle effecten activeren om te zien wat dit zal doen op onze performance. 

uncomment alle effecten en kijk eens naar je scene.

<EffectComposer>
    <Vignette
        offset={ 0.3 }
        darkness={ 0.9 }
        blendFunction={ BlendFunction.NORMAL }
    />
    <Glitch
        delay={ [ 0.5, 1 ] }
        duration={ [ 0.1, 0.3 ] }
        strength={ [ 0.2, 0.4 ] }
        mode={ GlitchMode.CONSTANT_MILD }
    />
    <Noise
        premultiply
        blendFunction={ BlendFunction.SOFT_LIGHT }
    />
    <Bloom
        mipmapBlur
        intensity={ 0.5 }
        luminanceThreshold={ 0 }
    />
    <DepthOfField
        focusDistance={ 0.025 }
        focalLength={ 0.025 }
        bokehScale={ 6 }
    />
    <ToneMapping mode={ ToneMappingMode.ACES_FILMIC } />
</EffectComposer>

04

PERFORMANCE

PERFORMANCE

Afhankelijk van de computer, pixel ratio, settings van de effects, etc ... is de frame rate nog redelijk ok. Onze Post processing zorgt ervoor dat de laagste aantal 'passes' uitgevoerd worden en combineert onze effecten in 1 shader.

Comment de effecten behalve ToneMapping en kijk naar het verschil.

<EffectComposer>
    {/* <Vignette
        offset={ 0.3 }
        darkness={ 0.9 }
        blendFunction={ BlendFunction.NORMAL }
    />
    <Glitch
        delay={ [ 0.5, 1 ] }
        duration={ [ 0.1, 0.3 ] }
        strength={ [ 0.2, 0.4 ] }
        mode={ GlitchMode.CONSTANT_MILD }
    />
    <Noise
        premultiply
        blendFunction={ BlendFunction.SOFT_LIGHT }
    />
    <Bloom
        mipmapBlur
        intensity={ 0.5 }
        luminanceThreshold={ 0 }
    />
    <DepthOfField
        focusDistance={ 0.025 }
        focalLength={ 0.025 }
        bokehScale={ 6 }
    /> */}
    <ToneMapping mode={ ToneMappingMode.ACES_FILMIC } />
</EffectComposer>

04

PERFORMANCE

PERFORMANCE

Kies dus wijselijk welke effecten je zal toevoegen en heb je geen nodig laat het dan volledig weg. Indien het meerwaarde heeft kan je die toevoegen maar soms kan iets toevoegen ook een omgekeerd effect hebben.

TECH3/8 - Postprocesssing

By Niels Minne

TECH3/8 - Postprocesssing

  • 49