Skip to content

Post-processing

<PostProcessing> mounts a stack of screen-space passes in a scene, beside World, not inside Game: Game’s children are DOM, and the stack draws over the canvas. No scene mounts one means no composer and no cost, so a game pays for the stack only where it uses it. The stack’s libraries load as a chunk of their own when a scene first mounts one, and the scene draws without the stack until they arrive.

Prop Type Default What it means
children ReactNode none The passes, in the order they draw: AmbientOcclusion, Bloom, Vignette, or a pass of @react-three/postprocessing’s own.
toneMapping ToneMappingMode | false ToneMappingMode.ACES_FILMIC The curve that maps the frame’s light to the screen, applied after every child. false skips it, for a child that tone maps itself.
multisampling number 4 Samples per pixel. The stack draws off the canvas and loses the renderer’s own antialiasing, so this puts it back; 0 turns it off.

A stack takes one of each pass: two of a kind share one set of settings. To turn a library pass on and off, set it from state the stack’s parent holds, so the stack renders again and picks up the change; the engine’s own passes can also be toggled from state inside a child. Ambient occlusion goes first among the children, so bloom and the vignette draw over the darkened contact rather than under it. Tone mapping always runs last, after every other pass, because a pass such as bloom reads the frame’s true brightness rather than the compressed screen curve. The daylight rig’s exposure still applies underneath it: the rig sets renderer.toneMappingExposure from the hour of day, and the composer’s tone-mapping curve reads that same exposure when it draws.

A glow around whatever is brighter than the threshold: the sun, a lamp, an emissive material.

Prop Type Default What it means
intensity number 0.6 How bright the glow is.
threshold number 0.85 The luminance, 0 to 1, a pixel must pass to glow.
radius number 0.7 How far the glow spreads, 0 to 1.

Darkens where surfaces meet: under a tree, at the foot of a wall.

Prop Type Default What it means
radius number 2 How far, in metres, a surface darkens another.
intensity number 2 How dark the contact is.
quality “performance” | “low” | “medium” | “high” | “ultra” “performance” The sample count’s preset.

Darker corners, which pull the eye to the middle of the screen.

Prop Type Default What it means
offset number 0.3 Where the darkening starts from the centre, 0 to 1.
darkness number 0.5 How dark the corners get, 0 to 1.

Roblox offers bloom, blur and colour correction as post effects under Lighting, with no ambient occlusion pass or vignette of its own. Unity and Unreal build the same passes into a volume-based post stack, and Godot’s WorldEnvironment resource does the same. The engine mounts them as components instead, so a pass turns on or off with the rest of a scene’s JSX rather than a separate settings object, and an agent reads its cost the same way it reads any other child of the scene.

The stack is a PostProcessing row in the devtools tree, with a leaf per pass: Bloom, AmbientOcclusion and Vignette. Each leaf shows the pass’s number props as sliders, and an edit shows on the next frame. A prop the scene changes replaces the edit, and Reset goes back to the props, as for a behaviour. Tone mapping and multisampling are not in the inspector: they are set where the stack mounts. The row cannot be deleted, because the stack’s component owns it.

Ambient occlusion, bloom and a vignette over the meadow, tone mapped with ACES:

import {
AmbientOcclusion,
Bloom,
PostProcessing,
Vignette,
World,
} from "@daniel-zarinski/engine";
export function MeadowScene() {
return (
<World map="meadow">
<PostProcessing>
<AmbientOcclusion />
<Bloom intensity={0.8} />
<Vignette darkness={0.6} />
</PostProcessing>
</World>
);
}

Client. The stack changes nothing in the world; each player’s browser draws its own frame through it.