Bloom

Multi-level bloom post-processing

Initializing WebGPU...
Source image

Quick Start

Loading...

Source

Loading...

Documentation

bloom

Multi-level bloom post-processing. Extracts bright regions, builds a mipmap pyramid with Jimenez 13-tap downsampling, applies separable Gaussian blur at each level, upsamples with tent filtering, and composites the result back onto the original image.

Quick Start

import { createBloom } from './gpu-modules/bloom/bloom';

const bloom = createBloom(device, { format: 'rgba8unorm', levels: 5 });

// Each frame — input and output are GPUTextures
bloom.render(sceneTexture, outputTexture, {
  threshold: 0.8,
  strength: 1.0,
  radius: 0.5,
  softKnee: 0.5
});

bloom.destroy();

API

createBloom(device, options?)

  • deviceGPUDevice
  • options.format — Texture format. Default 'rgba8unorm'.
  • options.levels — Number of mip levels in the bloom pyramid. Default 5.

Returns { render, destroy }.

render(input, output, params?)

Applies bloom from input texture to output texture. Both must have TEXTURE_BINDING usage; output must also have RENDER_ATTACHMENT.

  • params.threshold — Brightness threshold for bloom extraction. Default 0.8.
  • params.strength — Bloom intensity multiplier. Default 1.0.
  • params.radius — Blur radius scale. Default 0.5.
  • params.softKnee — Soft threshold transition width. Default 0.5.

How It Works

  1. Threshold — Extract pixels brighter than threshold (soft-knee smoothstep).
  2. Downsample — Build a mip chain using Jimenez 13-tap filter (avoids aliasing artifacts).
  3. Blur — Apply 9-tap separable Gaussian blur (horizontal + vertical) at each mip level.
  4. Upsample — Walk back up the chain with a 9-tap tent filter, additively combining levels.
  5. Composite — Add the bloom result to the original image, scaled by strength.

How to Modify

  • Change quality vs performance: Reduce levels for fewer blur passes (faster, less spread). Increase for wider, smoother bloom.
  • HDR pipeline: Change format to 'rgba16float' for HDR bloom. The threshold and composite math already works with HDR values.
  • Custom threshold: Edit fs_threshold in the WGSL to use a different extraction method (e.g., per-channel threshold, color-based selection).
  • Anamorphic bloom: Set the blur direction to only blur horizontally (edit the direction uniforms) for a cinematic streak effect.

Further Reading

Rationale

Bloom simulates the way bright light bleeds into surrounding areas in cameras and the human eye. It's one of the most common post-processing effects in games and real-time graphics — any scene with HDR lighting, emissive materials, or bright light sources benefits from bloom. Without it, bright areas look flat and clipped.

This module implements a production-quality bloom pipeline used in shipped AAA games, in a single self-contained WebGPU file.

Original Research

  • Jorge Jimenez (2014) — Next Generation Post Processing in Call of Duty: Advanced Warfare — The presentation that introduced the 13-tap downsample filter used in this module. The key insight is using a weighted combination of 13 bilinear taps instead of a simple box filter, which prevents aliasing and fireflies in the bloom. https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare/

  • Kawase (2003) — Frame Buffer Postprocessing Effects in DOUBLE-S.T.E.A.L — An earlier approach using iterative dual-blur that's cheaper but lower quality. Good context for understanding the design space.

Existing Implementations

Further Learning

  • LearnOpenGL: Bloom — Step-by-step tutorial explaining the bloom pipeline with diagrams. https://learnopengl.com/Advanced-Lighting/Bloom
  • Alexander Christensen: HDR Bloom — Practical guide to implementing bloom in a modern rendering pipeline, covers threshold, downsampling, and compositing.