refactor examples
This commit is contained in:
+245
-17
@@ -1,23 +1,251 @@
|
||||
# Examples
|
||||
# Exemples WSG
|
||||
|
||||
Each `.rs` file in this directory is a **standalone example** auto-discovered by Cargo
|
||||
(`cargo build -p wsg-lib --examples`). To run an example:
|
||||
Chaque exemple est autonome et illustre **un effet ou une fonctionnalité** spécifique
|
||||
de la bibliothèque. Tous utilisent l'API déclarative (`AppBuilder` + `AppHandler`).
|
||||
|
||||
```bash
|
||||
cargo run -p wsg-lib --example <name>
|
||||
## Lancer un exemple
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example <nom>
|
||||
```
|
||||
|
||||
| Example | Command | Description |
|
||||
|---------|---------|-------------|
|
||||
| `demo` | `cargo run -p wsg-lib --example demo` | **Showcase**: one of each primitive, procedural textures, directional + point + spot lights, a shadow-casting light, and a live orbital camera (drag / wheel zoom / `R` reset / `1`-`3` presets). |
|
||||
| `simple` | `cargo run -p wsg-lib --example simple` | Flat unlit quad (minimal declarative workflow, `AppBuilder` + auto scene). |
|
||||
| `cube` | `cargo run -p wsg-lib --example cube` | Textured cube (procedural checker) lit by a directional + point + spot light. |
|
||||
| `manual` | `cargo run -p wsg-lib --example manual` | Low-level workflow: `Context`, `Renderer`, `PipelineCache`, `Mesh` used directly (no `App` facade). |
|
||||
| `spot_test` | `cargo run -p wsg-lib --example spot_test` | Spot-light isolation: only one spot is on (near-zero ambient), cube rotates on two axes so the oriented beam is clearly visible. |
|
||||
| `shadow_test` | `cargo run -p wsg-lib --example shadow_test` | Shadow mapping: one directional light is the shadow caster (`set_shadow_caster(Some(0))`); a cube casts a PCF-softened shadow onto a thin ground slab. |
|
||||
| Exemple | Effet démontré |
|
||||
|---------|---------------|
|
||||
| `demo` | Showcase complet (tous les effets combinés) |
|
||||
| `bloom` | Post-process bloom (glow autour des zones brillantes) |
|
||||
| `hdr` | HDR + Tone Mapping (ACES) + contrôle d'exposition |
|
||||
| `emissive` | Matériaux émissifs (intensités croissantes 0 → 4.0) |
|
||||
| `shadow` | Shadow mapping (ombre portée directionnelle) |
|
||||
| `culling` | Culling GPU-driven (grille 20×20, objets hors frustum ignorés) |
|
||||
| `manual` | Workflow bas niveau (Context + Renderer + PipelineCache) |
|
||||
| `import` | Import de fichier OBJ (non graphique, stdout) |
|
||||
|
||||
## Conventions
|
||||
---
|
||||
|
||||
- Examples are **self-contained**: no assets loaded from disk (procedural textures, hardcoded geometry).
|
||||
- They use the declarative workflow (`AppBuilder` + `Scene`) except `manual`, which bypasses the `App` facade.
|
||||
- When adding a new example: create a `.rs` file in this directory, document it here, and reference it in the root README if appropriate.
|
||||
## `demo` — Showcase complet
|
||||
|
||||
Combine **tous** les effets : primitives LOD, textures procédurales, lumières
|
||||
(directional + point + spot), ombres, HDR/ACES, exposition, émissif, bloom, culling.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example demo
|
||||
```
|
||||
|
||||
### Touches
|
||||
|
||||
| Touche | Action |
|
||||
|--------|--------|
|
||||
| Glisser (LMB) | Orbiter la caméra |
|
||||
| Molette | Zoom |
|
||||
| `R` | Reset caméra |
|
||||
| `1` / `2` / `3` | Presets : face / côté / dessus |
|
||||
| `+` / `-` | Exposition ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposition |
|
||||
|
||||
---
|
||||
|
||||
## `bloom` — Post-process Bloom
|
||||
|
||||
Deux sphères émissives (orange intensité 2.0, bleue intensité 3.0) produisent un
|
||||
halo visible. Le cube et le sol servent de référence (non-émissifs).
|
||||
|
||||
Le bloom est un pipeline 4 passes GPU : threshold → blur H → blur V → composite.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example bloom
|
||||
```
|
||||
|
||||
### Touches
|
||||
|
||||
| Touche | Action |
|
||||
|--------|--------|
|
||||
| Glisser (LMB) | Orbiter la caméra |
|
||||
| Molette | Zoom |
|
||||
| `R` | Reset caméra |
|
||||
| `+` / `-` | **Bloom threshold** +0.1 / −0.1 |
|
||||
| `[` / `]` | **Bloom intensity** +0.1 / −0.1 |
|
||||
| `I` / `O` | **Bloom radius** +0.5 / −0.5 |
|
||||
| `E` / `Q` | Exposition ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposition |
|
||||
|
||||
### Ce qu'on voit
|
||||
|
||||
- **threshold bas** (0.0) : tout l'image "bloom" (effet très diffus).
|
||||
- **threshold élevé** (2.0+) : seules les sphères émissives brillantes produisent du glow.
|
||||
- **intensity 0.0** : pas de glow visible (même si le threshold extrait des pixels).
|
||||
- **radius grand** (10+) : le glow s'étend sur une grande zone.
|
||||
|
||||
---
|
||||
|
||||
## `hdr` — HDR + Tone Mapping
|
||||
|
||||
Démontre le rendu HDR avec la courbe ACES Filmic. Trois objets :
|
||||
|
||||
- **Cube** : éclairage normal (aucun émissif) — référence LDR.
|
||||
- **Sphère brillante** (émissif 3.0) : sans HDR, elle serait clampée à blanc.
|
||||
Avec ACES, les highlights "roulent" doucement vers le blanc (rolloff).
|
||||
- **Sphère sombre** (émissif 0.3) : reste sombre même à haute exposition.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example hdr
|
||||
```
|
||||
|
||||
### Touches
|
||||
|
||||
| Touche | Action |
|
||||
|--------|--------|
|
||||
| Glisser (LMB) | Orbiter la caméra |
|
||||
| Molette | Zoom |
|
||||
| `R` | Reset caméra |
|
||||
| `E` | **Exposition ×1.3** (plus clair) |
|
||||
| `Q` | **Exposition ÷1.3** (plus sombre) |
|
||||
| `0` | Reset exposition à 1.0 |
|
||||
|
||||
### Ce qu'on voit
|
||||
|
||||
- À exposition 1.0 : la sphère brillante est blanche mais avec des détails (rolloff ACES).
|
||||
- À exposition haute (E×E×E) : la scène s'éclaircit, la sphère brillante reste blanche
|
||||
(saturée), mais le cube gagne en détail.
|
||||
- À exposition basse (Q×Q) : tout s'assombrit, la sphère brillante devient orangée
|
||||
(les valeurs HDR > 1.0 sont compressées).
|
||||
|
||||
> **Note** : le tone mapper est compilé dans le pipeline au build. Pour comparer
|
||||
> ACES vs Reinhard, modifier `ToneMapper::Aces` → `ToneMapper::Reinhard` dans le source.
|
||||
|
||||
---
|
||||
|
||||
## `emissive` — Matériaux Émissifs
|
||||
|
||||
Cinq sphères alignées avec des intensités émissives croissantes :
|
||||
|
||||
| Sphere | Couleur | Intensité | Effet |
|
||||
|--------|---------|-----------|-------|
|
||||
| 1 | Gris | 0.0 | Aucune glow (référence) |
|
||||
| 2 | Orange | 0.5 | Légère lueur |
|
||||
| 3 | Jaune | 1.0 | Lueur visible |
|
||||
| 4 | Vert | 2.0 | Glow HDR (au-delà de 1.0) |
|
||||
| 5 | Bleu | 4.0 | Glow intense (saturation) |
|
||||
|
||||
Avec HDR, les intensités > 1.0 produisent un vrai "glow" (les valeurs dépassent
|
||||
[0,1] en espace linéaire). Sans HDR, elles seraient clampées à blanc.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example emissive
|
||||
```
|
||||
|
||||
### Touches
|
||||
|
||||
| Touche | Action |
|
||||
|--------|--------|
|
||||
| Glisser (LMB) | Orbiter la caméra |
|
||||
| Molette | Zoom |
|
||||
| `R` | Reset caméra |
|
||||
| `E` / `Q` | Exposition ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposition |
|
||||
| `C` | **Cycler le multiplicateur d'émissif** (1× → 2× → 0.5× → ...) |
|
||||
|
||||
### Ce qu'on voit
|
||||
|
||||
- La sphère 1 (intensité 0) est simplement éclairée par la lumière directionnelle.
|
||||
- Les sphères 2-5 brillent de leur propre lumière, indépendamment de l'éclairage.
|
||||
- `C` double ou réduit toutes les intensités en même temps (pour voir l'effet HDR).
|
||||
|
||||
---
|
||||
|
||||
## `shadow` — Shadow Mapping
|
||||
|
||||
Quatre objets (cube, sphère, cône, cylindre) sur un sol, éclairés par une lumière
|
||||
directionnelle qui projette des ombres. La qualité des ombres est contrôlée par
|
||||
`ShadowConfig` (taille de la shadow map, biais anti-acne).
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example shadow
|
||||
```
|
||||
|
||||
### Touches
|
||||
|
||||
| Touche | Action |
|
||||
|--------|--------|
|
||||
| Glisser (LMB) | Orbiter la caméra |
|
||||
| Molette | Zoom |
|
||||
| `R` | Reset caméra |
|
||||
| `1` | Vue de face |
|
||||
| `2` | Vue de côté |
|
||||
| `3` | **Vue de dessus** (voir la forme des ombres clairement) |
|
||||
| `L` | Changer la direction de la lumière (3 presets) |
|
||||
|
||||
### Ce qu'on voit
|
||||
|
||||
- Le cube tourne lentement → son ombre bouge sur le sol.
|
||||
- La sphère a une transition ombre/lumière douce (terminateur lisse).
|
||||
- Le cône produit une ombre triangulaire distincte.
|
||||
- En vue de dessus (`3`), on voit la forme exacte des ombres projetées.
|
||||
- La taille de la shadow map (1024 par défaut) détermine la résolution :
|
||||
modifier `SHADOW_MAP_SIZE` en haut du fichier pour tester 256 (pixelisé) ou 2048 (net).
|
||||
|
||||
---
|
||||
|
||||
## `culling` — GPU Frustum Culling
|
||||
|
||||
Une grille de **15×15 = 225 cubes** est placée sur un grand sol. Le culling
|
||||
GPU-driven (compute shader) détermine quels cubes sont visibles dans le frustum
|
||||
de la caméra et zéro leurs draw args indirects — **zéro coût CPU**.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example culling
|
||||
```
|
||||
|
||||
### Touches
|
||||
|
||||
| Touche | Action |
|
||||
|--------|--------|
|
||||
| Glisser (LMB) | Orbiter la caméra (regarder autour) |
|
||||
| Molette | Zoom in/out |
|
||||
| `R` | Reset (vue de dessus) |
|
||||
| `1` | Vue de face (les cubes derrière sont culled) |
|
||||
| `2` | Vue de côté |
|
||||
| `3` | **Vue de dessus** (voir toute la grille) |
|
||||
|
||||
### Ce qu'on voit
|
||||
|
||||
- En vue de dessus (`3`) : toute la grille 20×20 est visible.
|
||||
- Orbiter à 90° : les cubes derrière la caméra **ne sont pas dessinés** (culled).
|
||||
- Zoomer très près : seuls les cubes proches du plan de near sont rendus.
|
||||
- Les cubes tournent lentement (phases décalées) → le culling est dynamique
|
||||
(un cube peut entrer/sortir du frustum au cours d'une frame).
|
||||
|
||||
> **Note** : le culling est activé via `AppBuilder::with_culling(true)`. Le modifier
|
||||
> à `false` dans le source désactive le culling (tous les 400 cubes sont toujours
|
||||
> dessinés, même hors écran).
|
||||
|
||||
---
|
||||
|
||||
## `manual` — Workflow bas niveau
|
||||
|
||||
Démontre l'API **sans** la façade `App` : utilisation directe de `Context`,
|
||||
`Renderer`, `PipelineCache`, `Mesh`, `Material`. Rend un quad coloré (unlit).
|
||||
|
||||
Utile pour comprendre ce que la façade `App` encapsule.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example manual
|
||||
```
|
||||
|
||||
Pas de touches — rendu statique (quad unlit, 4 couleurs).
|
||||
|
||||
---
|
||||
|
||||
## `import` — Import de fichier OBJ
|
||||
|
||||
Exemple **non graphique** : parse un fichier `.obj` et affiche les statistiques
|
||||
(nombre de sommets, normales, UVs, indices, bounding box) sur stdout.
|
||||
|
||||
```sh
|
||||
# Avec un fichier :
|
||||
cargo run -p wsg-lib --example import --features import-obj -- /path/to/model.obj
|
||||
|
||||
# Sans argument (triangle de démonstration) :
|
||||
cargo run -p wsg-lib --example import --features import-obj
|
||||
```
|
||||
|
||||
Pas de touches — s'exécute et quitte.
|
||||
|
||||
Reference in New Issue
Block a user