Skip to main content

Bloom

Spread bright scene highlights into a controllable photographic glow. luma.gl provides a compact single-pass bloom effect, a composable HDR multiscale pipeline, and a separate WebGPU FFT convolution renderer for measured or generated optical point-spread functions.

GitHub

At a Glance

ImplementationExportBackendsSuitable for
Compact bloombloom from @luma.gl/effectsWebGPU and WebGL2A single inexpensive highlight-glow pass.
Multiscale HDR bloomcreateBloomShaderPassPipeline from @luma.gl/effectsWebGPU and WebGL2Configurable HDR scattering, temporal stabilization, and photographic lens effects.
FFT optical convolutionGPUConvolutionBloom from @luma.gl/experimentalWebGPUFull-image generated or measured RGB lens-response kernels.

Usage

import {ShaderPassRenderer} from '@luma.gl/engine';
import {createBloomShaderPassPipeline, toneMapping} from '@luma.gl/effects';

const renderer = new ShaderPassRenderer(device, {
colorFormat: 'rgba16float',
shaderPasses: [
createBloomShaderPassPipeline({
quality: 'high',
blurAlgorithm: 'dual-kawase',
downsample: 'auto',
threshold: 0.8,
intensity: 1,
scatter: 0.55,
reconstruction: 'bicubic',
temporalStability: 0.75,
lens: {starburstIntensity: 0.3, ghostIntensity: 0.15, dirtIntensity: 0.2}
}),
toneMapping
]
});

renderer.renderToScreen({
sourceTexture: hdrSceneTexture,
bindings: {lensDirtTexture}
});

For the compact implementation, place bloom directly in the shaderPasses array and provide uniforms: {bloom: {radius: 4, threshold: 0.8, intensity: 1}} when rendering.

Parameters

ParameterDefaultDescription
quality'high'Pyramid depth: low, medium, high, and ultra create two through five levels.
radius8Blur radius for the configurable HDR pipeline; compact bloom defaults to 4.
threshold0.8Scene-referred luminance at which highlights begin contributing to glow.
intensity1Strength of the reconstructed bloom contribution.
scatter0.55Relative contribution from progressively wider pyramid levels.
softKnee0.5Width of the smooth highlight-threshold transition.
blurAlgorithm'gaussian'Separable Gaussian filtering or the lower-pass-count 'dual-kawase' pyramid.
reconstruction'tent'Normalized tent filtering or four-bilinear-fetch 'bicubic' reconstruction.
downsample'auto'Select fused WebGPU compute when available; 'render' forces portable fragment stages.
resolutionScale1Multiplier applied to every extraction and reconstruction target.
fireflyReduction0Suppression strength for isolated, unusually bright source samples.
anamorphicRatio0Horizontal or vertical stretching, clamped between -1 and 1.
energyConservingfalseReplace additive thresholded glow with normalized, thresholdless scene scattering.
temporalStability0Contribution from neighborhood-clamped persistent glow history.
reuseRenderTargetstrueReuse expired extraction targets for compatible reconstruction stages.

exposure, exposureCompensation, previousExposure, tint, temporalReprojection, and temporalDepthThreshold provide additional control over camera response and motion-aware history. The default intermediate format is rgba16float to preserve unclamped highlight energy.

Performance by Quality

QualityPyramid levelsGaussian portableGaussian WebGPUDual-Kawase portableDual-Kawase WebGPU
low28 render passes6 render + 1 compute4 render passes2 render + 1 compute
medium312 render passes9 render + 1 compute6 render passes3 render + 1 compute
high416 render passes12 render + 1 compute8 render passes4 render + 1 compute
ultra520 render passes15 render + 1 compute10 render passes5 render + 1 compute

Counts describe the bloom pipeline itself; renderer presentation, optional lens artifacts, and optional history stages are additional. The fused compute path requires WebGPU, storage-write support for the chosen format, and sufficient storage bindings. Unsupported configurations automatically retain the portable render implementation.

Lens Effects and Temporal History

lens.starburstIntensity, lens.ghostIntensity, and lens.haloIntensity enable aperture-style diffraction streaks, mirrored lens-element reflections, and radial halos. When any of these are positive, all three effects share one additional half-resolution pass. Each starburst ray uses eight samples; a ghost uses one sample, or three with chromatic aberration.

lens.dirtIntensity samples an application-provided lensDirtTexture during the existing composite. Dirt alone therefore adds neither a render pass nor an intermediate target.

Enabling temporalStability adds one persistent half-resolution history texture and one extra resolve pass. temporalReprojection: true additionally requires caller-provided velocityTexture and depthTexture bindings, rejects disocclusions, and stores prior depth in the existing history alpha channel. previousExposure corrects accumulated history after camera-exposure changes.

FFT Optical Convolution

GPUConvolutionBloom applies a complete point-spread function in the frequency domain rather than approximating broad optical response with a local pyramid. It accepts a shared generated or measured kernel, or independent red, green, and blue kernels. Its packed FFT schedule processes the three channels together, while zero-padded guard bands prevent highlights from wrapping around opposite image edges.

At 1920 by 1080 with quarter-resolution sampling and the default 12.5% guard band:

ConfigurationFFT dimensionsComplex buffersSteady-state compute dispatches
Default guard band1024 x 51248 MiB45
guardBand: 0512 x 51224 MiB43

Changing the optical kernel requires 21 additional initialization dispatches for the guarded configuration. Chromatic ghosts, radial halo, lens dirt, temporal history, and optional GPU-resident exposure execute in the existing final compute stage.

Composition and Integration

Keep bloom in linear floating-point scene color after lighting and adaptive exposure, but before Tone Mapping. A typical HDR order is temporal reconstruction, auto exposure, bloom, and then the display transform.

deck.gl's existing PostProcessEffect can execute the compact bloom shader-pass descriptor. It does not execute named-target ShaderPassPipeline graphs or the separate WebGPU FFT renderer, and its default intermediate format is rgba8unorm; retaining unclamped HDR highlights therefore requires an integration that arranges floating-point scene and postprocessing targets.

Technical References