Renderer · type
OutputTransform
What happens to a shaded colour on its way to the framebuffer.
Explained in Hello world.
type OutputTransform = 'none' | 'srgb' | 'aces' | 'shoulder' | 'filmic'import type { OutputTransform } from '@driftengine/core';In depth
none writes it unchanged, which is what this renderer has always done and what its
worlds are authored against.
srgb applies the sRGB transfer function. This is not a stylistic choice: shading
maths is linear and a display is not, so writing linear values into an 8-bit
framebuffer crushes the midtones — a surface at 0.2 linear should read as 0.48 and
instead reads as 0.2. It is why an untransformed render looks dark and muddy in
exactly the places a lit one should look ordinary.
aces adds filmic tone mapping before that, rolling highlights off instead of
clipping them flat. Together they are what three.js does by default, which is why a
world ported from it looks wrong until this exists.
shoulder keeps sRGB's midtones exactly and eases only the highlights: past 0.8 the brightest
channel rolls toward 1 and the other two are scaled with it, so an overbright red spark stays
red where srgb clips each channel and turns its core pink and wide. It is the curve a ported
game's own resolve applied — for a port that has to match one — and it has none of ACES's toe or
desaturation. See HIGHLIGHT_SHOULDER_GLSL for the arithmetic.
filmic is a film curve shaped by five numbers — a slope, a toe, a shoulder and how far black
and white clip — that holds a mid grey of 0.18 at 0.18 where aces gives about 0.11, so a look
graded against such a curve is matched by its numbers (setFilmicCurve) rather than by a lookup
table. Applied by the composite alone, so it needs screenEffects and hdrScene; without them
every pass grades with aces and the renderer says so once. See filmicCurve.ts.