Why 100,000:1 does not fit on a screen
A real scene can span an enormous range of brightness: direct sunlight, a shaded doorway and a candle flame in the same frame can differ by five or six orders of magnitude. An HDR camera sensor or a physically based renderer captures that range as linear floating-point radiance, with no upper bound. A standard display, on the other hand, reproduces a contrast ratio closer to 100:1 or 1000:1, and even the best consumer HDR panels top out well short of what a bright outdoor scene actually contains. Tonemapping is the mapping from the first range to the second. Simply clipping every value above 1.0 to white loses the highlight detail; scaling everything down linearly by a fixed factor instead crushes the shadows into near-black. Neither is acceptable, so tonemapping needs a curve, not a scalar.
Global operators: Reinhard
Erik Reinhard's 2002 "photographic tone reproduction" operator, inspired by Ansel Adams' zone system, is the simplest curve that behaves well: divide luminance by one plus itself. Values near zero pass through almost unchanged, and values that grow toward infinity asymptote gently toward one instead of clipping. The extended version adds a white point Lwhite so the brightest true reflectors in the scene can still reach display white instead of settling for a dull grey:
simple Reinhard: Ld = L / (1 + L) extended (with white): Ld = L * (1 + L / Lwhite^2) / (1 + L)
A global operator applies exactly the same curve to every pixel regardless of its neighbours. That makes it cheap, temporally stable across frames of video, and free of the halo artefacts that plague local methods — but it cannot preserve strong local contrast in both a bright window and a dark interior in the same shot, because both regions are forced through the same function.
Filmic ACES: borrowing film's highlight rolloff
The Academic Color Encoding System's filmic curve approximates how photochemical film already responds to light: an S-shaped curve with a soft, gradual highlight rolloff rather than a hard clip, which keeps saturated colours from turning neon and keeps bright regions looking like overexposed film instead of a flat digital ceiling. Because it was tuned to match how cinematographers already expect highlights to behave, it needs little or no per-shot adjustment, which is why it became the default tonemapper in most modern game engines and renderers. A widely used compact fit by Krzysztof Narkowicz approximates the full ACES pipeline in a single expression:
ACES fitted (Narkowicz, 2016), x = linear colour a = 2.51, b = 0.03, c = 2.43, d = 0.59, e = 0.14 Ld = clamp( (x * (a*x + b)) / (x * (c*x + d) + e), 0, 1 )
Local operators: Drago and Durand's bilateral split
Frederic Drago's 2003 adaptive logarithmic operator varies the base of a logarithmic compression curve with a bias parameter, giving finer control over how aggressively the high and low ends of the range are squeezed than a plain logarithm allows. Fredo Durand and Julie Dorsey went further in 2002 by making the operator genuinely local: split the log-luminance image into a smooth base layer, built with an edge-preserving bilateral filter, and a detail layer that is whatever the bilateral filter removed. Compress only the base layer aggressively — that is where the huge dynamic range lives — and leave the detail layer alone, then add them back together.
base = bilateralFilter( log(L) ) // edge-preserving, large-scale detail = log(L) - base // fine texture, small-scale Ld = exp( compress(base) + detail ) // squeeze only the smooth part
Because the bilateral filter respects strong edges, texture and micro-contrast survive even after the overall range is compressed a hundredfold — but if the filter's radius or edge threshold is mismatched to the image, luminance can leak across a strong edge and reappear as a visible halo ring once the layers are recombined.
Choosing an operator
Real-time rendering and games favour filmic or ACES because it is temporally stable frame to frame and needs no per-shot tuning, whereas a naive local operator can flicker as the camera moves and the "smooth" base layer shifts. Photography workflows lean on local operators, or on multi-exposure fusion, to produce the punchy, detail-everywhere "HDR look." Scientific and false-colour visualisation often wants a plain, exact global mapping instead, precisely because local contrast enhancement can mislead a viewer about the underlying data. One detail applies to every operator: naive per-channel tonemapping in RGB desaturates bright colours, so most implementations tonemap luminance alone and reapply the original hue and saturation, or operate in a perceptually uniform colour space, to keep colours looking natural through the whole compression.
Frequently asked questions
What is the difference between HDR capture and tonemapping?
HDR capture or rendering produces floating-point radiance values that can exceed what any display can show, often spanning a range of 10,000 to 1 or more. Tonemapping is the separate downstream step that compresses those linear values into the roughly 0 to 1 range a screen can actually reproduce.
Why do local tonemapping operators sometimes produce halos?
Local operators split the image into a smooth base layer and a detail layer, compressing only the base. If the edge-preserving filter used to build that base layer lets luminance leak across a strong edge, the recombined image shows a visible bright or dark ring following the edge — the classic tonemapping halo.
Why does ACES look more natural than simple Reinhard?
ACES filmic tonemapping approximates the soft, S-shaped highlight rolloff of photochemical film, so bright saturated areas fade gently toward white instead of clipping or flattening to grey. Simple Reinhard compresses every luminance level with the same curve and can desaturate and flatten highlights by comparison.
Try it live
Everything above runs in your browser — open HDR Tonemapping Operators and change the parameters while it is running. Nothing is installed, nothing is uploaded, the whole model lives in one tab.
▶ Open HDR Tonemapping Operators simulation