Files
wsg/docs/user/fog.md
T
Jérôme Bousquié 24fbafc810 réorg doc
2026-09-25 19:08:20 +02:00

3.9 KiB
Raw Blame History

Brouillard de distance (Fog)

Principe

Le brouillard de distance fond les objets vers une couleur prédéfinie en fonction de leur distance à la caméra. C'est l'outil standard pour :

  • Masquer le bord du monde rendu — illusion d'un monde infini (Skyrim, GTA, Minecraft)
  • Donner de la profondeur — effet atmosphérique naturel
  • Camoufler les transitions — chargement de tuiles, LOD pops

Activation

use wsg_lib::prelude::*;

let app = AppBuilder::new()
    .with_fog(FogConfig::exponential2([0.7, 0.75, 0.85], 0.06))
    .build()
    .await?;

Sans .with_fog(), le brouillard est désactivé — zéro coût GPU (la branche shader est jamais prise).

Modes

Mode Formule Usage
Linear saturate((far - d) / (far - near)) Cutoff net entre deux distances
Exponential exp(-density × d) Brouillard naturel (forêt, lac)
Exponential2 exp(-density² × d²) Départ progressif, cutoff net — idéal pour masquer

Constructeurs

// Linéaire : fondu entre near et far
FogConfig::linear([0.7, 0.8, 0.9], 5.0, 50.0)

// Exponentiel : fondu naturel
FogConfig::exponential([0.6, 0.7, 0.8], 0.03)

// Exponentiel² : masquage de bord de monde
FogConfig::exponential2([0.7, 0.75, 0.85], 0.08)

Paramètres

Champ Type Description
mode FogMode Linéaire / Exponentiel / Exponential2
color [f32; 3] Couleur du brouillard (RGB, espace linéaire)
near f32 Distance début (mode linéaire uniquement)
far f32 Distance fin, brouillard complet (mode linéaire)
density f32 Densité (modes exp / exp²). Typique : 0.01–0.3

Choisir la couleur

La couleur du brouillard doit correspondre à la couleur du ciel/clear color pour un effet "monde infini" seamless. Avec HDR + ACES, utiliser des valeurs linéaires cohérentes avec le tone mapping.

Choisir la densité (exp²)

Pour masquer le bord du monde à une distance D :

density ≈ 2.0 / D

Exemples :

  • Monde visible jusqu'à 25 unités → density = 0.08
  • Monde visible jusqu'à 50 unités → density = 0.04
  • Monde visible jusqu'à 100 unités → density = 0.02

Changement à l'exécution

// Dans update() :
if key_pressed(KeyCode::Digit1) {
    app.renderer_mut().set_fog(Some(FogConfig::linear([0.7, 0.8, 0.9], 5.0, 30.0)));
}
if key_pressed(KeyCode::Digit4) {
    app.renderer_mut().set_fog(None); // désactiver
}

Le changement prend effet au frame suivant.

Pipeline

Main pass (shader fragment)
  ↓
  Lighting → final_rgb
  ↓
  FOG: mix(final_rgb, fog_color, 1 - fog_factor)   ← ici
  ↓
  → HDR texture / swapchain
  ↓
  (Bloom) → Tone Mapping → surface

Le brouillard s'applique avant le tone mapping : les valeurs HDR restent non clampées, et le TM applique la courbe ACES/Reinhard au résultat déjà brouillé. Résultat : le brouillard est perceptuellement cohérent.

Compatibilité

Avec OK ? Note
HDR + TM ✅ Fog avant TM (recommandé)
Bloom ✅ Le bloom extrait les zones brillantes du résultat post-fog
MSAA ✅ Indépendant (rasterizer vs fragment shader)
Culling GPU ✅ Indépendant (culling décide quoi dessiner, fog décide la couleur)
Shadows ✅ L'ombre est calculée avant le fog

Limitations (v1)

  • Scene-level uniquement : un seul brouillard pour toute la scène. Un brouillard par matériau nécessiterait un paramètre additionnel dans le bind group par objet.
  • Distance euclidienne : pas de brouillard volumétrique ni directionnel.
  • Couleur fixe : pas de gradient de couleur avec la distance.

Exemple

Voir lib/examples/effects/fog.rs : 15 cubes en rangée + 5 sphères sur un plan 80×80, avec commutation runtime entre les 3 modes.

cargo run -p wsg-lib --example fog --features "all-prims"