This commit is contained in:
Jérôme Bousquié
2026-09-25 13:43:59 +02:00
parent 9614156848
commit 8ece89ccba
22 changed files with 1998 additions and 245 deletions
+133
View File
@@ -0,0 +1,133 @@
# 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"
```