@@ -188,3 +188,4 @@ The architecture docs live in `docs/tech/` and are written in **French**. Each d
9. ✅ **Window resize (Étape 11, Phase 4.4)** — `App::resize` reconfigures the surface (`Context::configure`) and recreates the depth texture (`Renderer::resize_depth`) together on each `WindowEvent::Resized`, so color and depth attachments always match. Guards against 0×0 (minimize). The surface format is re-synced to the Renderer and Scene if it ever changes. (Done 2026-09-18; verified at runtime on the `cube` example.)
10. ✅ **Multi-lighting (Étape 12, Phase 4.2)** — the scene now carries a global light list (directional + point) with a white ambient, uploaded into the per-frame `FrameUniforms` array each frame. `Scene::add_directional_light` / `add_point_light` / `set_ambient` / `clear_lights` configure it; `FrameUniforms::default()` (one white directional along +Z + white ambient) reproduces the pre-multi-light look exactly. The `standard` fragment accumulates ambient + all lights; the `cube` example adds a warm point light on top of the default directional. (Done 2026-09-18.)
11. ✅ **Spot lights (Étape 13, Phase 4.2)** — spot lights (oriented cone + half-angle) added on top of the multi-lighting system. `Scene::add_spot_light(pos, dir, color, intensity, radius, half_angle)` registers a spot light; the `standard` fragment accumulates a spot term with a smoothed penumbra (half-angle ± 0.1 rad) and linear attenuation. `Light` grew from 48 to 64 bytes (added `dir_angle`); `FrameUniforms` from 576 to 704 bytes (added `num_spot`). Non-regression: default scene unchanged. The `cube` example adds a green spot light aimed at the cube. (Done 2026-09-18.)
12. ✅ **Shadows — shadow mapping (Étape 14, Phase 4.2, optionnel)** — classic two-pass shadow mapping on a **single** light (directional or spot), selected by `Scene::set_shadow_caster(index)`. A depth-only pass (`shadow_shader.wgsl` + dedicated `shadow_pipeline`) renders the scene into a 1024² `Depth32Float` shadow map (`Renderer`-owned, slope-scaled depth bias); the `standard` fragment re-projects each fragment into light space and applies a **PCF 3×3** comparison-sampler test (bind group **@3**, shared). `FrameUniforms` grew from 704 to 784 bytes (`shadow_light_index`, `light_view_proj`, `shadow_params`). Shadows are **off by default** (`shadow_caster = None`) so `simple`/`cube`/`manual`/`spot_test` are unchanged. The `shadow_test` example casts a soft shadow from a rotating cube onto a ground slab. (Done 2026-09-19.)
- **spot** → projection **perspective** depuis le sommet du cône.
### Pourquoi ce choix ?
- Coût, lisibilité et validation simples : une texture, une passe, un VP lumière, un échantillon PCF.
- S'aligne sur l'architecture existante (matrices par frame, object bind group réutilisé).
- Le multi-shadow et les ombres point seront des extensions incrémentales (voir §6 « Évolutions »),
pas une réécriture.
---
## 2. Décisions (D1..D8)
| # | Décision |
|---|----------|
| **D1** | **Une seule lumière ombreuse** par frame, sélectionnée par index (tuple `(enable, index)`). Desactivée par défaut (index = `MAX_LIGHTS`). API : `Scene::set_shadow_caster(index)`. |
| **D2** | **Shadow map** : `DEPTH_FORMAT` (Depth32Float), résolution **1024×1024** par défaut, `usage = RENDER_ATTACHMENT | TEXTURE_BINDING`, 1 mip. Propriété du `Renderer` (comme la depth texture de scène). |
| **D3** | **Matrice `light_view_proj` calculée sur CPU** chaque frame par le `Renderer` (depuis `scene.shadow_caster()` + la lumière + un centre/rayon de scène). Ortho pour directionnelle, perspective pour spot. Uploadée dans `FrameUniforms` (tampon frame existant, `min_binding_size: None` → extension transparente). |
| **D4** | **Pipeline ombre dédiée** (vertex-only, `fragment: None`) : layout = [group 0 : `light_view_proj`, group 1 : `object_layout`**réutilisé**]. Elle réutilise donc directement `object_cache` (bind groups par entité déjà réécrits chaque frame). |
| **D5** | **PCF (Percentage Closer Filtering)** : échantillon comparateur (`sampler_comparison` + `texture_depth_2d`) + petit kernel 3×3 dans le shader, **slope-scaled depth bias** sur la pipeline ombre (`DepthBiasState { constant, slope_scale, clamp }`) + un petit bias constant dans la comparaison pour supprimer l'acné. |
| **D6** | **Ombre ponctuelle (cube map) hors périmètre** : documentée en §6, PAS implémentée à l'Étape 14. |
| **D7** | **Non-régression** : ombres éteintes par défaut → exemples `simple`/`cube`/`manual`/`spot_test` inchangés (pas de changement de leur rendu). Le groupe 3 (shadow) reste lié sur toutes les pipelines mais l'échantillonnage est porté par `options[1]`/index. |
| **D8** | **Résolution shadow** configurable plus tard ; constante `SHADOW_MAP_SIZE = 1024` maintenant (setter + recréation de texture reportés — voir §6). |
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.