# 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 ```rust 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 ```rust // 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 ```rust // 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 ```text 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. ```sh cargo run -p wsg-lib --example fog --features "all-prims" ```