Files
wsg/docs/user/bloom.md
T
Jérôme Bousquié 35aeb769a8 refactor examples
2026-09-25 10:19:24 +02:00

3.3 KiB
Raw Blame History

Bloom (Étape 23)

Le bloom est un post-process qui crée un effet de "glow" autour des zones brillantes de l'image. Les pixels dont la luminance dépasse un seuil sont extraits, floutés, puis ajoutés à l'image originale.

Prérequis : le bloom nécessite l'HDR (AppBuilder::with_hdr). Sans HDR, les valeurs sont déjà clampées à [0,1] et il n'y a rien de "brillant" à extraire.

Activation

use wsg_lib::prelude::*;

let app = AppBuilder::new()
    .with_hdr(ToneMapper::Aces)       // requis
    .with_bloom(BloomConfig {
        threshold: 1.0,               // seuil de luminance HDR
        knee: 0.5,                    // largeur du soft-knee
        intensity: 0.8,               // intensité du glow
        radius: 4.0,                  // rayon du blur (pixels, demi-rés)
        ..Default::default()
    })
    .build()
    .await?;

BloomConfig

Champ Type Défaut Description
threshold f32 1.0 Seuil de luminance (unités HDR linéaires). Seuls les pixels > seuil contribuent au bloom.
knee f32 0.5 Largeur du soft-knee. Plus grand = transition plus douce.
intensity f32 0.8 Multiplicateur appliqué au résultat flouté avant addition à l'HDR.
radius f32 4.0 Rayon du blur en pixels (à la demi-résolution). Plus grand = glow plus étendu.

Mise à jour runtime

// Dans le handler (fn update):
if app.bloom_enabled() {
    app.set_bloom_config(BloomConfig {
        intensity: new_intensity,
        ..app.bloom_config()
    });
}

Les changements prennent effet au frame suivant (les uniforms sont ré-écrits chaque frame).

Pipeline (4 passes GPU)

Scene ──→ HDR (full res, Rgba16Float)
              │
              ├──→ [1] Threshold (full → half res)
              │         Soft-knee: smoothstep(knee, knee+1, lum)
              │
              ├──→ [2] Blur H (half res)
              │         9-tap Gaussian séparable, direction = (1/w, 0)
              │
              ├──→ [3] Blur V (half res)
              │         9-tap Gaussian séparable, direction = (0, 1/h)
              │         (ping-pong: écrit dans la texture bright)
              │
              └──→ [4] Composite (full res)
                        output = HDR + bloom × intensity
                        (écrit dans une 3e texture full-res)
                          │
                          ▼
                    Tone Mapping (lit le composite)
                          │
                          ▼
                    Surface (sRGB)

Coût

  • Sans bloom (défaut) : zéro overhead. Le TM lit directement la texture HDR.
  • Avec bloom : 4 passes supplémentaires (1 full-res + 3 half-res) + 3 textures intermédiaires. Le coût est modéré car le blur est en demi-résolution.

Non-régression

  • with_bloom() sans with_hdr() → warning + no-op (le bloom est ignoré).
  • Sans with_bloom() → le TM lit la texture HDR directement (comportement Étape 20 inchangé).

Limitations (MVP)

  • Un seul niveau de mip (pas de multi-mip "soft" bloom à la Unreal).
  • Pas de directional bloom.
  • Le blur est un Gaussian 9-taps (qualité suffisante pour un glow "soft").
  • Pas de bloom séparé par couche (pas de "bloom mask" par matériau).