Files
wsg/docs/ROADMAP.md
T
2026-09-18 17:29:45 +02:00

12 KiB

type, title, description, tags, status, generated
type title description tags status generated
Roadmap WSG Engine Development Roadmap Development roadmap for the WSG engine from prototype to full-featured 3D rendering engine
roadmap
development
planning
wsg-lib
3d-rendering
stable
by at
human:jerome 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 (résolue 2026-09-17). « 3D + éclairage Phong » (ROADMAP 1.3 + 1.5) est atteinte : le rendu automatique n'est plus plat. L'infrastructure (Étapes 3+4, 2026-09-16) — standard_shader.wgsl Phong (matrice projection * view * world + lumière directionnelle), uniform buffers branchés (frame : view/proj/cam_pos + lumière ; par mesh : world dérivé du Transform), Renderer écrivant chaque frame la caméra active et la matrice monde de chaque entité — est branchée sur l'exemple cube (Étape 5, 2026-09-17) : un cube unitaire éclairé qui tourne à l'écran via App::render_scene. Le shader basic est supprimé : le 2D plat devient la variante unlit de standard (Renderer::set_unlit(true)). Objectif MVP atteint.


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

  • glam = "0.33" ajouté (lib/Cargo.toml) — déjà présent, utilisé par math/transform.rs et resources/camera.rs
  • slotmap retiré — décision prise : String IDs pour le MVP ; slotmap reporté à l'étape "handles typés" (voir Notes de Décision)
  • Module math/ / transform.rs:
    • Struct Transform { translation: Vec3, rotation: Quat, scale: Vec3 }
    • Méthode to_matrix() -> Mat4 pour calculer la matrice locale
    • Struct Camera { position: Vec3, target: Vec3, up: Vec3 } : resources/camera.rs — enrichi en Étape 4.3 (fov/near/far + with_perspective)
    • 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) — fait :
    • positions: Vec<[f32; 3]> (obligatoire)
    • indices: Option<Vec<u16>> (optionnel)
    • normals: Option<Vec<[f32; 3]>> (pour Phong) — plus uvs: Option<Vec<[f32; 2]>>
    • colors: Option<Vec<[f32; 4]>> — fait (Étape 8, 8.1, 2026-09-18) : décidé en DRAFT Étape 8 (D1) ; le shader lit la couleur unlit, elle est donc portée dans Geometry. Conversion Geometry -> Vec<Vertex> via Geometry::to_vertices() (D6) pour l'upload.
  • Refactorer Mesh pour contenir — fait (Étape 8, 8.3, 2026-09-18) :
    • geometry: Arc<Geometry> (rétention CPU, D5) + accesseur geometry()
    • vertex_buffer: wgpu::Buffer
    • index_buffer: Option<wgpu::Buffer>
    • Construction via Mesh::from_geometry(device, Arc<Geometry>, material) (D4) ; les anciennes voies Mesh::new/with_material (&[Vertex]) sont supprimées.
    • Scene::create_mesh(id, Geometry, Option<&str>) (8.4) ; exemples cube/simple/manual réécrits sur Geometry (8.5).
  • Ajouter un mesh de test (cube unitaire) en exemple — fait (helper cube_geometry dans l'exemple cube, Étape 5, 2026-09-17)

État (2026-09-18) : Mesh porte son matériau (mesh.material: Option<Arc<Material>>, Étape 7) et une source de vérité CPU partagée (geometry: Arc<Geometry>, Étape 8). Mesh ne porte pas de transform : un même mesh est partagé par plusieurs entités ; le transform vit sur Entity.

1.3 Shader Phong Minimal

  • Créer standard_shader.wgsl (Étape 2, 2026-09-16) :
    • Vertex shader : projection * view * world * position
    • Fragment shader : éclairage directionnel (+ hémisphérique)
    • Uniforms : view, proj, cam_pos, light_dir, light_color, options
  • Mettre à jour Material / pipeline pour supporter les uniforms du shader Phong (bind group layouts frame+object, Étape 3) — désormais branché sur l'exemple cube (Étape 5, 2026-09-17)

1.4 Scene avec identifiants (MVP : String IDs)

  • 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
  • Méthodes : add_mesh(), get_mesh(), add_material(), add_entity(), iter_entities(), remove_entity()
  • 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

  • Uniform buffer pour la frame : view, proj, cam_pos, light_dir (Étapes 3+4) — écrit chaque frame depuis la caméra active
  • Uniform buffer par mesh : world (calculée sur CPU depuis transform.to_matrix(), Étape 4.2)
  • 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 — fait (Étape 5, 2026-09-17 : brancher standard sur l'exemple cube + mesh cube + rotation via App::render_scene)

Phase 2️⃣ — Scène enrichie

Objectif : Étoffer la Scene au-delà du MVP.

Les ressources sont, pour le MVP, identifiées par String IDs (décision actée — voir Notes de Décision). Une migration vers des handles typés (slotmap générationnel) reste planifiée quand l'éviction/les performances le justifieront (voir 1.4, « reporté »).

2.1 Camera dans la Scene

  • 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 (Étape 10 : resources::Texture, from_rgba8/bytes/file, Rgba8UnormSrgb, sampler linear/repeat)
  • Ajouter uvs: Option<Vec<[f32; 2]>> dans Geometry (prérequis Étape 10, déjà présent dans le code — seul l'échantillonnage manquait)
  • BindGroup pour les textures dans le shader (Étape 10 : groupe @2 sampler+texture sur toutes les pipelines, placeholder blanc)
  • Material supporte une texture diffuse (Étape 10 : Material.texture + texture_bind_group, placeholder si None)

4.2 Éclairage avancé

  • Lumières hémisphériques (déjà dans le standard_shader : mélange hémisphérique, Étape 2)
  • Support multi-lumières (directionnelles, ponctuelles)
  • Shadows (optionnel)

4.3 Optimisations

  • Batching par Material (réduction des state changes GPU)
  • 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) (Étape 11, 2026-09-18) → 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. (D4 : App::resize compare l'ancien/nouveau format et re-synchronise Renderer (set_format) + Scene (init_gpu) ; cas pathologique, structuré non exercé couramment)

Géré en Étape 11 (2026-09-18) : la surface est désormais reconfigurée à chaque Resized et la depth texture recréée en même temps (helper create_depth_texture isolé, Étape 9, D3). Le present mode FIFO reste figé (voir Notes de Décision).


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
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
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