3.9 KiB
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"