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
+2
View File
@@ -23,6 +23,8 @@ GPU graphics background is required.
| [Mesh & primitives](mesh.md) | Procedural generators + file import (OBJ), feature-gated |
| [HDR & tone mapping](hdr.md) | Offscreen float render + ACES/Reinhard, opt-in via `with_hdr` |
| [MSAA (anti-aliasing)](msaa.md) | Multi-sample edge smoothing, opt-in via `with_msaa(4)` |
| [Fog (distance)](fog.md) | Distance fog (3 modes), masks world edges, opt-in via `with_fog()` |
| [DoF (depth of field)](dof.md) | Cinematic bokeh blur, focus plane, opt-in via `with_dof()` |
| [GPU-driven rendering](gpu-driven.md) | GPU world matrices + indirect draws, opt-in frustum culling |
| [Camera & input](camera-input.md) | Active camera, orbital controller, unified keyboard/mouse state |
| [Examples](examples.md) | The 7 repo examples, the advanced `manual` workflow, adding your own example |
+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"
```