diff --git a/README.md b/README.md index bed4544..f5f18ae 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,8 @@ fn main() { // Renderer + shader cache (falls back to the embedded shader if the file is missing) // `set_unlit(true)` selects flat 2D rendering (the quad below is drawn in NDC space, unlit). - let mut renderer = Renderer::new(&context, format); + // Étape 9 : width/height size the depth buffer allocated inside the Renderer. + let mut renderer = Renderer::new(&context, format, 800, 600); renderer.set_unlit(true); let mut cache = PipelineCache::new(Arc::new(context.device.clone())); cache.register_shader("standard", utils::STANDARD_SHADER_PATH).unwrap(); diff --git a/docs/DRAFT.md b/docs/DRAFT.md index 5335b29..81d9b51 100644 --- a/docs/DRAFT.md +++ b/docs/DRAFT.md @@ -1,6 +1,119 @@ -# DRAFT — Prochaine étape +# DRAFT — Étape 9 : Depth Buffer -> Document de travail de la prochaine étape (ROADMAP). Rempli au début de chaque étape -> et vidé à sa complétion. Source de vérité = code + README.md. +> 📅 **Rédigé le 2026-09-18.** Fonctionnel validé, plan à valider avant implémentation. +> Source de vérité = code + README.md. Ce document est vidé à la complétion de l'étape. -_Prêt pour la prochaine étape._ +## Contexte (constat d'observation) + +L'exemple `cube` en rotation montre que **la profondeur n'est pas calculée** : les faces +les plus lointaines ne sont pas masquées par les faces plus proches. Causes identifiées dans +le code (observation du 2026-09-18) : +- `lib/src/pipeline/pipeline_cache.rs` → `depth_stencil: None` à la création du pipeline (L233). +- `lib/src/core/renderer.rs` → les deux render passes (`render`, `render_scene`) ne posent + **aucun** `depth_stencil_attachment` ; seul un `color_attachments` est fourni (L194, L239). +- Aucune texture de profondeur n'est créée, donc aucun z-test n'est exécuté. + +**Conclusion** : non implémenté (pas un bug). C'est un prérequis de correction du rendu avant +les textures (Phase 4.1), tel que décidé avec l'utilisateur le 2026-09-18. + +## Objectif + +Activer le test de profondeur (z-buffer) sur tous les chemins de rendu (`render` ET `render_scene`) +pour que les faces cachées soient correctement masquées. + +## Décisions (validées le 2026-09-18) + +- **[x] D1 (format)** — *(validée 2026-09-18)* : texture de profondeur `TextureFormat::Depth32Float`, + valeur de clear `1.0` (portée maximale), `depth_compare: Less`, `depth_write_enabled: true`. +- **[x] D2 (portée)** — *(validée 2026-09-18)* : le depth buffer est posé sur **les deux** render + passes (bas niveau `render` et haut niveau `render_scene`), pas seulement `render_scene`, pour + garder la cohérence du flux 2D. +- **[x] D3 (résolution)** — *(validée 2026-09-18)* : la texture de profondeur est allouée à la taille + de la surface initiale. **Le resize est planifié comme chantier dédié** dans `docs/ROADMAP.md` + (Phase 4.4, avec recréation de la depth texture en même temps que la reconfiguration de la surface), + hors périmètre de l'Étape 9. On créera un helper `create_depth_texture` isolé pour rendre ce + recreate trivial plus tard. +- **[x] D4 (échantillonnage)** — *(validée 2026-09-18, YAGNI)* : aucune texture de profondeur n'est + échantillonnée pour l'instant (pas de shadow mapping ni de post-processing) — on n'a donc pas + besoin de l'exposer dans un bind group. Simple render target + state pipeline suffisent ; le bind + group sera ajouté quand le shadow mapping arrivera. + +## Plan d'implémentation + +### 9.1 — Créer la texture de profondeur dans `Renderer` *(terminée et vérifiée le 2026-09-18)* +- [x] Ajouter un champ `depth_view: wgpu::TextureView` au `Renderer` (avec helper pour allouer + `depth_texture` + `depth_view` à partir de `device` et de la taille surface). +- [x] Taille : `width`/`height` passés à `Renderer::new` (aujourd'hui il ne reçoit que `format`). + Portée : avantage à `create_depth_texture(device, width, height, format)`. +- [x] `TextureDescriptor` : `size: Extent3d { width, height, depth_or_array_layers: 1 }`, + `mip_level_count: 1`, `sample_count: 1`, `dimension: D2`, + `format: wgpu::TextureFormat::Depth32Float`, + `usage: RENDER_ATTACHMENT`, `label: Some("depth texture")`. + +### 9.2 — Attacher le depth au render pass *(terminée et vérifiée le 2026-09-18)* +- [x] Dans `render_scene` (renderer.rs) : ajouter `depth_stencil_attachment: Some(...)` au + `RenderPassDescriptor`, avec `depth_ops: Operations { load: Clear(1.0), store: Store }`. +- [x] Même ajout dans `render` (renderer.rs) pour la cohérence du chemin bas niveau. + +### 9.3 — Activer le depth-stencil state dans le pipeline *(terminée et vérifiée le 2026-09-18)* +- [x] Dans `pipeline_cache.rs` (L233) : remplacer `depth_stencil: None` par + `Some(DepthStencilState { format: Depth32Float, depth_write_enabled: Some(true), + depth_compare: Some(CompareFunction::Less), stencil: StencilState::default(), + bias: DepthBiasState::default() })` — note : en wgpu 30, `depth_write_enabled` et + `depth_compare` sont des `Option` (le DRAFT initial les donnait nus). +- [x] Le format du depth doit matcher celui de la texture (D1 : `Depth32Float`) — garanti par la + constante partagée `DEPTH_FORMAT` (pipeline_cache.rs), réexportée via `pipeline::mod`. + +### 9.4 — Vérification *(terminée et vérifiée le 2026-09-18)* +- [x] `cargo fmt --all` (aucun diff attendu), `cargo check --workspace` (zéro warning), + `cargo test --workspace` (vert : 3 tests), `cargo doc` (pas de `missing_docs`). +- [x] Lancer l'exemple `cube` (`cargo run -p wsg-lib --example cube`) : tourne sans erreur backend + (le z-buffer est accepté par wgpu, aucun format mismatch) — faces arrière masquées. +- [x] Lancer `simple` (rendu plat via `render_scene`) : pas de régression, tourne sans erreur GPU. + +## Point d'étape + +- [x] Valider D1–D4 avant implémentation. *(fait — 2026-09-18 : D1 Depth32Float, D2 les deux passes, + D3 resize planifié dans RoADMAP Phase 4.4, D4 YAGNI)* +- [x] Caser 9.1–9.4, validation verte, exemples OK. *(fait — 2026-09-18)* +- [x] Deux commits séparés : `refactor(...)` (9.1–9.3) puis `docs(...)` (9.4) + README/DRAFT. + *(fait — refactor fca5d72 puis docs)* +- [x] Rédiger le bilan et ouvrir la suite (textures/matériaux Phase 4.1). + +--- + +## Bilan de l'Étape 9 — Depth Buffer (terminée le 2026-09-18) + +La profondeur est maintenant calculée sur **tous** les chemins de rendu : + +- **1 texture de profondeur partagée** (`Depth32Float`, D1), allouée par le `Renderer` à la taille + de la surface initiale, gardée vivante par le champ `_depth_texture` (rétention) et vue via + `depth_view`. +- **Les deux render passes** (`render` bas niveau et `render_scene` haut niveau) posent un + `depth_stencil_attachment` identique (clear `1.0` / store), ce qui masque les faces arrière du + cube en rotation (D2). +- **Toutes les pipelines** déclarent un `DepthStencilState` cohérent (write `true`, compare `Less`) + via la constante partagée `DEPTH_FORMAT` — impossible d'avoir un format pipeline ≠ texture. + +### Décisions appliquées +- **D1** : `Depth32Float`, clear `1.0`, compare `Less`, write `true`. ✓ +- **D2** : profondeur posée sur `render` ET `render_scene`. ✓ +- **D3** : texture à la taille initiale ; le resize (recréation de la depth texture à chaque + changement de taille, couplée à la reconfiguration surface) est planifié en **ROADMAP Phase 4.4**. + Le helper `create_depth_texture` isolé rend ce recreate trivial. ✓ +- **D4** (YAGNI) : pas de bind group présentant la profondeur ; simple render target + state + pipeline. Le bind group attendra le shadow mapping. ✓ + +### API modifiée (breaking) +- `Renderer::new(context, format)` → `Renderer::new(context, format, width, height)` — + les appelants (`app.rs`, `manual.rs`, `README.md`) ont été mis à jour en conséquence. + +### Commits de l'étape +- `fca5d72` refactor(renderer): activate depth buffer on all render paths (9.1–9.3) +- *(docs — 9.4 : DRAFT coché + bilan, README mis à jour)* + +### Suite logique +Ouvrir la Phase 4.1 (Textures / matériaux) — le z-buffer était le prérequis de lisibilité : les +faces arrière étant désormais masquées, un cube texturé sera correctement rendu. + +_Fin de l'Étape 9._ diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index c8d08fc..3ddbda0 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -161,6 +161,17 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z } - [ ] Level of Detail (LOD) - [ ] HDR + Tone Mapping (optionnel) +### 4.4 Gestion du Resize (cycle de vie Surface + Depth) +- [ ] Handler `WindowEvent::Resized` dans `AppRunner::window_event` (`app.rs`) + → recalculer `size`, prévenir de ne pas rendre tant que la taille est invalide (0). +- [ ] Reconfigurer la surface (`Context::configure`) à la nouvelle taille. +- [ ] Recréer la depth texture à la nouvelle taille (`Renderer::resize_depth(width, height)`) + — le helper `create_depth_texture` isolé (Étape 9, D3) rend ce recreate trivial. +- [ ] Collecte du nouveau format si la configuration change (srgb etc.) → re-valider la compat pipeline. + +> Reporté hors de l'Étape 9 (depth buffer) : l'app ne gère aujourd'hui aucun resize — la surface +> n'est configurée qu'au démarrage (`resumed`). Chantier dédié, acté en D3 (2026-09-18). + --- ## Phase 5️⃣ — Documentation & Polish @@ -182,3 +193,4 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z } | **World Matrix CPU → MVP, GPU → Phase 3** | Le MVP est plus simple avec un uniform par mesh ; la migration GPU-driven est progressive | | **String IDs pour le MVP, slotmap reporté** | Le code et le README utilisent des String IDs (simples, sûrs, figés avant la boucle de rendu) ; `ARCHI_ARENES.md` reste la cible "handles typés" pour plus tard. La dépendance `slotmap` a été retirée tant qu'elle est inutilisée | | **Present mode FIFO figé pour l'instant** | Le swapchain utilise `PresentMode::Fifo` avec `desired_maximum_frame_latency: 2` (double buffering vsync) — défaut sûr : pas de tearing, énergie minimale, zéro artefact. On **gèle ce choix** ; `Mailbox` (triple buffering) pourra être exposé en option et `Immediate` restera réservé à l'offscreen, **on s'occupera du present mode le moment venu** (quand le pipeline GPU-driven arrivera, Phase 3) — ce n'est pas bloquant pour les étapes 1-2 | +| **Resize planifié (avec recréation de la depth texture), acté en D3 (2026-09-18)** | L'app ne gère aucun resize aujourd'hui (surface configurée une seule fois au démarrage). La depth texture créée à l'Étape 9 devra être recréée au resize **en même temps** que la reconfiguration de la surface — d'où un helper `create_depth_texture` isolé. Chantier dédié planifié en **Phase 4.4**, hors périmètre de l'Étape 9 |