134 lines
3.9 KiB
Markdown
134 lines
3.9 KiB
Markdown
# 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 `examples/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"
|
||
```
|