Files
wsg/docs/ROADMAP.md
T
Jérôme Bousquié f10e249898 feat(renderer): active camera wired to frame uniforms (Étape 4.3)
- Camera enrichie: fov/near/far stockés, Default (pos (0,0,3), 45°, near 0.1,
  far 100), with_perspective(), projection_matrix(aspect) depuis les params
  stockés (au lieu de les passer en argument).
- Scene porte une caméra active: set_camera()/camera() (défaut Camera::default).
- Renderer::render_scene(view, scene, aspect) écrit chaque frame view/proj/
  cam_pos réels dans le buffer frame (write_frame_uniforms) avant de dessiner;
  le Renderer garde le handle du frame_buffer. Le chemin bas-niveau render()
  conserve les valeurs par défaut (identité).
- App::render_scene calcule l'aspect depuis window.inner_size() (le Renderer
  reste indépendant de la fenêtre).

Docs synchronisées: DRAFT (4.3 coche), README (statut 3D-infra + quick ref),
PLAN (caméras), ROADMAP (1.1/1.3/1.5/2.3).

Validation: check workspace+examples 0 warning, test (Pod + wgsl) OK, doc 0
warning, fmt propre. Le rendu 3D visible attend Étape 5 (brancher standard).
2026-09-16 17:25:50 +02:00

169 lines
9.3 KiB
Markdown

---
type: Roadmap
title: WSG Engine Development Roadmap
description: Development roadmap for the WSG engine from prototype to full-featured 3D rendering engine
tags: [roadmap, development, planning, wsg-lib, 3d-rendering]
status: stable
generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
---
# Roadmap WSG — Prototype → Moteur Complet
> Basé sur l'architecture existante (ARCHI_APP, ARCHI_ARENES, ARCHI_CPU_GPU, ARCHI_RENDU).
> Objectif : prototype fonctionnel d'abord, enrichissement progressif ensuite.
>
> **Point de départ (état réel au 2026-09-16 — la source de vérité est README.md).**
> Les fondations suivantes existent et fonctionnent déjà ; cette roadmap décrit la **trajectoire à
> venir** à partir de cet état (elle reprend les étapes 1-4 du README avant la montée GPU-driven) :
> - Workflow manuel (`Context` + `Renderer` + `PipelineCache`) : ✅ fonctionnel (exemple `manual`).
> - Façade `App` / `AppBuilder` / `AppHandler` : ✅ **Scene auto-render** (2026-09-16) — la vue de frame
> est exposée (`Frame::view()`), `render()` dessine la scène en une passe groupée
> (`App::render_scene`) et la présentation est automatique dans `App::run` (exemple `simple`).
> - `Scene` avec identifiants **String** (décision prise — voir tableau Notes de Décision) : 🚧 enregistrement seul.
> - `Camera` / `Transform` et `glam` : types et mathématiques présents (`math/`, `resources/camera.rs`),
> initialement non branchés au pipeline — **désormais branchés** (caméra active + matrices monde écrites
> chaque frame, Étape 4.3, 2026-09-16 ; voir §1.1/1.5 ci-dessous).
> **Étape suivante (prochaine itération) — « 3D + éclairage Phong » (ROADMAP 1.3 + 1.5).**
> Le rendu automatique est aujourd'hui **plat** : le `basic_shader.wgsl` interprète les positions comme
> déjà en NDC, sans matrice monde/vue/projection ni lumière. **Une grande partie de l'infrastructure est
> déjà en place (Étapes 3+4, 2026-09-16)** : le `standard_shader.wgsl` Phong (matrice
> `projection * view * world` + lumière directionnelle) existe et valide ; les uniform buffers sont
> branchés (frame : view/proj/cam_pos + lumière ; par mesh : `world` dérivé du `Transform`) ; le `Renderer`
> écrit chaque frame la caméra active (via `Scene::set_camera`/`camera()`) et la matrice monde de chaque
> entité. **Reste à faire** pour un mesh 3D éclairé à l'écran : brancher `standard` sur un exemple et
> ajouter un mesh de test (cube). Objectif MVP : **un mesh 3D éclairé à l'écran**.
---
## Phase 1️⃣ — Prototype MVP : Un Mesh 3D éclairé à l'écran
**Objectif** : Afficher un cube (ou autre mesh) 3D avec un éclairage Phong basique.
### 1.1 Dépendances & Mathématiques
- [x] `glam = "0.33"` ajouté (`lib/Cargo.toml`) — déjà présent, utilisé par `math/transform.rs` et `resources/camera.rs`
- [x] `slotmap` **retiré** — décision prise : **String IDs pour le MVP** ; slotmap reporté à l'étape "handles typés" (voir Notes de Décision)
- [x] Module `math/` / `transform.rs`:
- [x] Struct `Transform { translation: Vec3, rotation: Quat, scale: Vec3 }`
- [x] Méthode `to_matrix() -> Mat4` pour calculer la matrice locale
- [x] Struct `Camera { position: Vec3, target: Vec3, up: Vec3 }` : resources/camera.rs — enrichi en Étape 4.3 (fov/near/far + `with_perspective`)
- [x] Fonctions `view_matrix()` et `projection_matrix(fov, aspect, near, far)` (Étape 4.3 : `projection_matrix(aspect)` utilise fov/near/far stockés)
### 1.2 Geometry & Mesh
- [ ] Créer struct `Geometry` (math/geometry.rs) :
- [ ] `positions: Vec<[f32; 3]>` (obligatoire)
- [ ] `indices: Option<Vec<u16>>` (optionnel)
- [ ] `normals: Option<Vec<[f32; 3]>>` (pour Phong)
- [ ] Refactorer `Mesh` pour contenir :
- [ ] `geometry: Arc<Geometry>`
- [ ] `vertex_buffer: wgpu::Buffer`
- [ ] `index_buffer: Option<wgpu::Buffer>`
- [ ] `transform: Transform` (état CPU)
- [ ] Ajouter un mesh de test (cube unitaire) en exemple
### 1.3 Shader Phong Minimal
- [x] Créer `standard_shader.wgsl` (Étape 2, 2026-09-16) :
- [x] Vertex shader : projection * view * world * position
- [x] Fragment shader : éclairage directionnel (+ hémisphérique)
- [x] Uniforms : `view`, `proj`, `cam_pos`, `light_dir`, `light_color`, `options`
- [x] Mettre à jour `Material` / pipeline pour supporter les uniforms du shader Phong (bind group layouts frame+object, Étape 3) — `standard` n'est pas encore branché sur un exemple
### 1.4 Scene avec identifiants (MVP : String IDs)
- [x] `Scene` implémentée avec **String IDs** (`HashMap<String, Arc<Mesh>>`, `...Material`, entités) — état actuel validé ; décision : rester en String IDs pour le MVP
- [x] Méthodes : `add_mesh()`, `get_mesh()`, `add_material()`, `add_entity()`, `iter_entities()`, `remove_entity()`
- [x] Caméra active dans la `Scene` : `set_camera()` / `camera()` (Étape 4.3)
- [ ] **Reporté (étape "Handles typés")** : migrer vers `slotmap` générationnel (`MeshId`/`MaterialId`) quand l'éviction/les performances le justifieront
### 1.5 Rendu du Prototype
- [x] Uniform buffer pour la frame : `view`, `proj`, `cam_pos`, `light_dir` (Étapes 3+4) — écrit chaque frame depuis la caméra active
- [x] Uniform buffer par mesh : `world` (calculée sur CPU depuis `transform.to_matrix()`, Étape 4.2)
- [x] `Renderer::render_scene()` itère sur les entités de la Scene et dessine chacune (liaison bind groups frame+object)
- [ ] Exemple fonctionnel : un cube éclairé tourne à l'écran — **à faire** (Étape 5 : brancher `standard` sur un exemple + mesh cube)
---
## Phase 2️⃣ — Système de Ressources complet
**Objectif** : Étoffer la Scene avec tous les types de ressources.
### 2.1 Arènes complètes
- [ ] `SlotMap<MaterialId, Material>`
- [ ] `SlotMap<TextureId, Texture>` (struct de base)
- [ ] `SlotMap<LightId, Light>` (struct de base)
- [ ] `SlotMap<EntityId, Entity>` pour les entités de la scène
### 2.2 Entités & Hiérarchie
- [ ] Struct `Entity { mesh_id: Option<MeshId>, material_id: Option<MaterialId>, transform: Transform }`
- [ ] `Scene::add_entity()` → retourne `EntityId`
- [ ] `Scene::iter_entities()` → pour le render loop
### 2.3 Camera dans la Scene
- [x] Intégrer `Camera` comme ressource de la Scene (Étape 4.3 : `Scene::set_camera` / `camera()`, caméra active unique)
- [ ] Permettre plusieurs caméras (actuelle/inactive) et une sélection par identifiant (`scene.set_active_camera(camera_id)`)
- [ ] Exposer une caméra orbitale contrôlable (exemple final, Phase 5)
---
## Phase 3️⃣ — GPU-Driven Rendering
**Objectif** : Déléguer les calculs de transformation et culling au GPU (suivre ARCHI_CPU_GPU.md).
### 3.1 Compute Shader
- [ ] Buffer `TransformBuffer` (CPU → GPU) : positions/rotations/échelles brutes
- [ ] Buffer `MatrixBuffer` (GPU calculé) : World Matrices finales
- [ ] Compute shader : calcul des World Matrices pour tous les meshes
### 3.2 Frustum Culling GPU
- [ ] Ajouter `BBox` dans `Geometry` (center + extents)
- [ ] Buffer `BoundingBoxBuffer` (CPU → GPU, statique)
- [ ] Compute shader : culling basé sur la frustum de caméra
- [ ] Buffer `IndirectDrawBuffer` rempli par le GPU
### 3.3 Rendu Indirect
- [ ] `draw_indexed_indirect()` au lieu de draw calls individuels
- [ ] Un seul command draw pour tous les objets visibles
---
## Phase 4️⃣ — Fonctionnalités Avancées
**Objectif** : Qualité visuelle et performances.
### 4.1 Textures
- [ ] Struct `Texture` avec chargement d'image
- [ ] Ajouter `uvs: Option<Vec<[f32; 2]>>` dans `Geometry`
- [ ] BindGroup pour les textures dans le shader
- [ ] `Material` supporte une texture diffuse
### 4.2 Éclairage avancé
- [ ] Support multi-lumières (directionnelles, ponctuelles)
- [ ] Lumières hémisphériques
- [ ] Shadows (optionnel)
### 4.3 Optimisations
- [ ] Batching par Material (réduction des state changes GPU)
- [ ] Level of Detail (LOD)
- [ ] HDR + Tone Mapping (optionnel)
---
## Phase 5️⃣ — Documentation & Polish
- [ ] Exemple complet : mesh texturé, éclairé, avec caméra orbitale
- [ ] Documentation API (`docs/ARCHI_SCENE.md`)
- [ ] Tests unitaires : `Geometry`, `Scene`, `Transform`
- [ ] README mis à jour avec les nouvelles fonctionnalités
---
## Notes de Décision
| Décision | Raison |
|----------|--------|
| **Normals dès Phase 1** | Nécessaires pour le shader Phong ; sans elles, pas d'éclairage |
| **UVs en Phase 4** | Inutiles avant les textures ; on garde `Geometry` simple au départ |
| **BBox en Phase 3** | Utile uniquement pour le frustum culling GPU |
| **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 |