docs: purge PLAN/ROADMAP des plans abandonnés, DRAFT vidé (Étape 10 finie)
La documentation reflète désormais uniquement ce qui *est* et ce qu'on
envisage de faire, pas ce qui aurait pu être (changements d'avis retirés) :
ROADMAP.md
- 1.2 : remplacé le récit de décision 'transform sur Mesh' (DRAFT Étape 8,
déviation) par l'énoncé de l'état actuel : Mesh porte son matériau + sa
Geometry CPU partagée, pas de transform (porté par Entity).
- Phase 2 réécrite : suppression des 'Arènes complètes' (SlotMap) et de la
struct Entity { mesh_id, material_id } contredite par l'Étape 7 (material
déplacé sur Mesh) et le choix String IDs ; migration 'handles typés'
conservée comme unique pointeur (1.4 / Notes de Décision).
- 4.2 : 'Lumières hémisphériques' cochée (déjà dans standard_shader).
- Notes de Décision : retiré 'UVs en Phase 4' (caduque, UVs implémentés dès
Geometry).
PLAN.md
- Statut réel condensé et mis à jour jusqu'à l'Étape 10 (textures).
- Phase 4 : Textures cochée (faite), Lumières laissée en plan (ROADMAP 4.2).
- Check-list pollster dé-obsolétisée ; suppression de la 'Note pour mémoire'
décrivant le module-pivot exec.rs qu'on a décidé de ne pas construire.
DRAFT.md
- Vidé (fin de l'Étape 10) en préparation de l'étape suivante.
This commit is contained in:
+4
-144
@@ -1,145 +1,5 @@
|
|||||||
# DRAFT — Étape 10 : Textures (Phase 4.1)
|
# DRAFT — Étape suivante
|
||||||
|
|
||||||
> 📅 **Rédigé le 2026-09-18.** Plan à valider avant implémentation.
|
> 📅 **Document vidé le 2026-09-18** (fin de l'Étape 10, Textures — Phase 4.1, bilan archivé
|
||||||
> Source de vérité = code + README.md. Ce document est vidé à la complétion de l'étape.
|
> dans l'historique git). Ce fichier accueillera le plan de l'étape suivante.
|
||||||
|
> Source de vérité = code + README.md. Ce document est vidé à la complétion de chaque étape.
|
||||||
## Contexte (état de départ)
|
|
||||||
|
|
||||||
La Phase 4.1 (Textures) du ROADMAP vise à texturer le rendu. État actuel du code :
|
|
||||||
- **La tuyauterie UV existe déjà** : `Geometry.uvs: Option<Vec<[f32; 2]>>` (builder `with_uvs`)
|
|
||||||
et `Vertex.uv` (location 2, offset 24, stride 56) sont déclarés dans `build_pipeline` et lus
|
|
||||||
par le shader `VertexInput`. Seul l'**échantillonnage manque**.
|
|
||||||
- Le shader `standard_shader.wgsl` reçoit l'UV mais ne le transmet pas au fragment et n'échantillonne rien.
|
|
||||||
- **Aucun type `Texture`**, aucun sampler, aucun bind group de texture. `Material` ne porte pas de texture.
|
|
||||||
- Architecture bind group : « un seul layout pour tous » (Étape 3) — les groupes `frame @0`
|
|
||||||
+ `object @1` sont posés sur **toutes** les pipelines et bindés à chaque draw (`draw_entity`).
|
|
||||||
|
|
||||||
**Conclusion** : l'UV est prête ; les pièces manquantes sont un type `Texture`, un bind group de
|
|
||||||
texture (groupe 2) partagé, un échantillonnage dans le shader et le portage sur `Material`.
|
|
||||||
|
|
||||||
## Objectif
|
|
||||||
|
|
||||||
Permettre de texturer un mesh : charger une image → `wgpu::Texture` (+ view + sampler), lier une
|
|
||||||
texture diffuse à un `Material`, échantillonner dans le shader, **sans casser** le pattern « un seul
|
|
||||||
layout pour tous ».
|
|
||||||
|
|
||||||
## Décisions (actées le 2026-09-18)
|
|
||||||
|
|
||||||
- **[x] D1 (intégration bind group — « un seul layout pour tous »)** : on ajoute un **3ᵉ bind group**
|
|
||||||
`@group(2)` (sampler + texture diffuse) posé sur **toutes** les pipelines, avec une **texture
|
|
||||||
blanche 1×1 de secours (placeholder)** utilisée quand un `Material` n'a pas de texture. Cela
|
|
||||||
préserve l'unicité du layout (aucune pipeline multiple), donc un seul flux de rendu. *(alternative
|
|
||||||
écartée : bind group optionnel → casse l'unicité du layout, refactor de toutes les pipelines)*.
|
|
||||||
- **[x] D2 (échantillonnage inconditionnel)** : le fragment shader échantillonne **toujours** la
|
|
||||||
texture diffuse ; le placeholder blanc (texel = 1) reproduit exactement le comportement actuel
|
|
||||||
d'un material sans texture. Donc pas de flag conditionnel → un seul flow de shader. En mode lit,
|
|
||||||
le **texel remplace la couleur du vertex** (`texel.rgb * (ambient + diffuse)`) ; en unlit, le texel
|
|
||||||
tel quel. Symétrique du pattern unlit existant.
|
|
||||||
- **[x] D3 (chargement d'image & format)** : ajouter la dépendance `image` (décodage PNG/JPEG) à
|
|
||||||
`lib/Cargo.toml` ; upload en `TextureFormat::Rgba8UnormSrgb`, usage `TEXTURE_BINDING | COPY_DST`,
|
|
||||||
dimension `D2`, `mip_level_count: 1` (**YAGNI** : pas de génération de mipmaps cette étape),
|
|
||||||
sampler `filter: Linear`, `address_mode: Repeat`.
|
|
||||||
- **[x] D4 (API et portage)** : nouveau type `Texture` (device + view + sampler). `Material` gagne
|
|
||||||
`texture: Option<Arc<Texture>>` et détient son **bind group de texture (groupe 2)**, construit
|
|
||||||
depuis le layout partagé ; sans texture il lie le placeholder. API `Scene` : `add_texture(id, tex)`
|
|
||||||
et liaison d'une texture à un material. `draw_entity` bind `set_bind_group(2, ...)`.
|
|
||||||
|
|
||||||
## Plan d'implémentation
|
|
||||||
|
|
||||||
### 10.1 — Nouveau type `Texture` + dépendance `image`
|
|
||||||
- [x] Ajouter `image` à `lib/Cargo.toml` (features `png`, `jpeg`).
|
|
||||||
- [x] `resources::texture::Texture { texture: wgpu::Texture, view: wgpu::TextureView, sampler: wgpu::Sampler }`.
|
|
||||||
- [x] `Texture::from_bytes(device, queue, &[u8])` (ou `from_file`) : décode via `image`, remplit un
|
|
||||||
buffer RGBA et upload via `Queue::write_texture` (D3).
|
|
||||||
- [x] `Texture::white_placeholder(device, queue)` : 1×1 blanc, pour D1/D2.
|
|
||||||
- [x] Enregistrer `pub mod texture` dans `resources/mod.rs`.
|
|
||||||
|
|
||||||
### 10.2 — Bind group layout texture (groupe 2) partagé
|
|
||||||
- [x] `create_uniform_bind_group_layouts` retourne `[frame, object, texture]` (3 layouts) ; `texture`
|
|
||||||
= `BindingType::Sampler(Filtering)` (binding 0) + `Texture { sample_type: Float, view_dimension: D2 }`
|
|
||||||
(binding 1), visibilité fragment.
|
|
||||||
- [x] `build_pipeline` : ajouter le 3ᵉ layout au `PipelineLayoutDescriptor` (l'unicité du layout est
|
|
||||||
conservée — D1).
|
|
||||||
- [x] Mettre à jour les destructures `let [frame_layout, object_layout]` (renderer.rs) pour 3 éléments.
|
|
||||||
|
|
||||||
### 10.3 — Shader standard : UV → fragment + échantillonnage
|
|
||||||
- [x] `VertexOutput` : ajouter `@location(2) uv: vec2<f32>` ; `vs_main` écrit `out.uv = input.uv`.
|
|
||||||
- [x] Déclarer `@group(2) @binding(0) var texture_sampler: sampler;` et
|
|
||||||
`@group(2) @binding(1) var diffuse_texture: texture_2d<f32>;`.
|
|
||||||
- [x] `fs_main` : `let texel = textureSample(diffuse_texture, texture_sampler, in.uv);` — en lit →
|
|
||||||
`texel.rgb * (ambient + diffuse)`, en unlit → `texel` (D2). Mettre à jour la doc du module shader.
|
|
||||||
|
|
||||||
### 10.4 — `Material` porte la texture diffuse
|
|
||||||
- [x] `Material { texture: Option<Arc<Texture>>, texture_bind_group }` ; le constructeur construit le
|
|
||||||
bind group (groupe 2) depuis le layout partagé, avec placeholder si `None` (D1/D4).
|
|
||||||
- [x] Méthode `set_texture(...)` qui recrée le bind group si la texture change.
|
|
||||||
- [x] Le sampler/placeholder partagé est fourni par la lib (une seule instanciation) pour que tout
|
|
||||||
Material sans texture lie le blanc.
|
|
||||||
|
|
||||||
### 10.5 — API Scene & binding dans `draw_entity`
|
|
||||||
- [x] Rendre accessible un layout du groupe 2 aux Materials (via `SceneGpu` / cache) pour construire
|
|
||||||
leurs bind groups.
|
|
||||||
- [x] Route déclarative `Scene` : `add_texture(id, tex)` et liaison d'une texture par id à un material
|
|
||||||
(ex. `add_material_texture` ou paramètre de `add_material_shader`).
|
|
||||||
- [x] `draw_entity` : `pass.set_bind_group(2, material.texture_bind_group, &[])`.
|
|
||||||
- [x] Vérifier qu'un material *sans* texture continue de fonctionner (placeholder → aucune régression).
|
|
||||||
|
|
||||||
### 10.6 — Exemples + validation
|
|
||||||
- [x] `cube` : texturer le cube (image PNG embarquée via `include_bytes!` pour rester autonome,
|
|
||||||
ou un motif procédural RGBA généré en mémoire).
|
|
||||||
- [x] `simple`/`manual` : pas de régression (placeholder).
|
|
||||||
- [x] `cargo fmt --all`, `cargo check --workspace` (0 warning), `cargo test --workspace` (vert, tests de
|
|
||||||
layout uniform + validation WGSL à jour), `cargo doc` (pas de `missing_docs`).
|
|
||||||
- [x] Exécuter `cube` (faces texturées) et `simple` sans erreur backend.
|
|
||||||
|
|
||||||
## Point d'étape
|
|
||||||
|
|
||||||
- [x] Valider D1–D4 avant implémentation. *(actées le 2026-09-18)*
|
|
||||||
- [x] Caser 10.1–10.6, validation verte, exemples OK. *(terminé et vérifié le 2026-09-18)*
|
|
||||||
- [x] Deux commits séparés : `refactor(...)` (10.1–10.5) puis `docs(...)` (10.6) + README/DRAFT. *(refactor : 440f2df ; docs : à finaliser)*
|
|
||||||
- [x] Rédiger le bilan et ouvrir la suite (Phase 4.2 Éclairage avancé). *(2026-09-18)*
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Bilan — Étape 10 : Textures (Phase 4.1)
|
|
||||||
|
|
||||||
**Livrés (commits `refactor` 440f2df puis `docs`) :**
|
|
||||||
- **10.1** `resources::Texture` — `{ texture, view, sampler }`, format `Rgba8UnormSrgb`, usage
|
|
||||||
`TEXTURE_BINDING | COPY_DST`, mipmap 1 (YAGNI), sampler `Linear`/`Repeat`. Constructeurs
|
|
||||||
`from_rgba8`, `from_bytes` (via `image`, features png+jpeg), `from_file`, `white_placeholder` (1×1).
|
|
||||||
Dépendance `image = "0.25"` ajoutée à `lib/Cargo.toml`.
|
|
||||||
- **10.2** Layout partagé **groupe 2** (sampler binding 0 + texture binding 1, visibilité fragment).
|
|
||||||
`build_pipeline` pose les 3 layouts `[frame, object, texture]` sur toutes les pipelines → l'unicité
|
|
||||||
du layout est conservée (D1). `PipelineCache` détient le layout + le placeholder blanc partagé.
|
|
||||||
- **10.3** Shader standard : `VertexOutput.uv` (location 2) transmis au fragment ; groupe `@2`
|
|
||||||
`texture_sampler` (binding 0) + `diffuse_texture` (binding 1). Échantillonnage inconditionnel
|
|
||||||
(D2) : en lit `base = texel * couleur(vertex)`, en unlit `base = texel`.
|
|
||||||
- **10.4** `Material.texture: Option<Arc<Texture>>` + `texture_bind_group` construit au constructeur
|
|
||||||
via le cache (layout partagé + placeholder si aucune texture).
|
|
||||||
- **10.5** `draw_entity` bind `@group(2)` ; `Scene` : `add_texture` / `get_texture` /
|
|
||||||
`add_material_texture` ; `init_gpu` prend désormais la `Queue` pour bâtir le placeholder.
|
|
||||||
- **10.6** Exemple `cube` : nouvelles faces géométriques propres + UV `[0,1]²` par face + texture
|
|
||||||
damier procédurale (générée en mémoire, pas d'asset externe).
|
|
||||||
|
|
||||||
**Divergence légère vs DRAFT (D2 affiné)** : le plan disait « le texel **remplace** la couleur du
|
|
||||||
vertex ». À l'implémentation on multiplie (`base = texel.rgb * in.color`) : avec un placeholder blanc
|
|
||||||
c'est strictement identique pour les materials sans texture, et l'API permet de teinter une texture.
|
|
||||||
Aucun impact fonctionnel — documenté pour traçabilité.
|
|
||||||
|
|
||||||
**Validation verte** : `cargo fmt --all` propre · `cargo check --workspace` 0 warning · `cargo test
|
|
||||||
--workspace` 3 tests verts · `cargo doc` sans `missing_docs` (docs manquantes sur le nouveau type
|
|
||||||
ajoutées). Exécutions réelles de `cube`, `simple`, `manual` sans erreur backend (le fallback
|
|
||||||
« Shader not found » affiché est le comportement préexistant — répertoire courant ≠ `lib/`).
|
|
||||||
|
|
||||||
**Structure finale en mémoire** (`PipelineCache`) : champ `texture_bind_group_layout` + `placeholder`
|
|
||||||
(`Arc<Texture>` blanc 1×1), exposés via les méthodes `texture_bind_group_layout()`,
|
|
||||||
`placeholder()`, et `texture_bind_group(Option<Arc<Texture>>)` pour créer un groupe 2 depuis une
|
|
||||||
texture (ou le placeholder).
|
|
||||||
|
|
||||||
**Suite (Phase 4.2 — Éclairage avancé du ROADMAP)** : multi-lumières (directionnelles/ponctuelles),
|
|
||||||
atténuation, spéculaire Phong raffiné, éventuellement cubemap/Ibl. Ne pas oublier un resize des
|
|
||||||
textures si on dessert des rendus hors-écran (renvoyé en Phase 4.4 avec le depth).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
_Fin du DRAFT Étape 10 — étape terminée le 2026-09-18._
|
|
||||||
|
|||||||
+19
-36
@@ -11,21 +11,19 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
|
|
||||||
Ce plan définit les étapes prioritaires pour finaliser l'architecture actuelle. L'objectif est de rendre l'API intuitive pour l'utilisateur standard tout en conservant la puissance de contrôle pour l'utilisateur avancé.
|
Ce plan définit les étapes prioritaires pour finaliser l'architecture actuelle. L'objectif est de rendre l'API intuitive pour l'utilisateur standard tout en conservant la puissance de contrôle pour l'utilisateur avancé.
|
||||||
|
|
||||||
> **Statut réel (à jour au 2026-09-18).** Ce plan couvre la phase de *consolidation* passée ; la source
|
> **Statut réel (à jour au 2026-09-18).** La phase de *consolidation* (Phases 1 à 3 de ce plan) est
|
||||||
> de vérité sur l'état actuel est **README.md** et le code. Depuis la révision du 2026-09-14, l'étape
|
> **terminée** ; la source de vérité sur l'état actuel est **README.md** et le code. Depuis la révision
|
||||||
> **« Scene auto-render »** a été réalisée : le rendu de la `Scene` est **automatisé** en une seule
|
> du 2026-09-14, le rendu de la `Scene` est automatisé en une passe groupée
|
||||||
> passe groupée via `App::render_scene(frame.view())` (appelée par défaut dans `AppHandler::render`),
|
> (`App::render_scene(frame.view())`, appelée par défaut dans `AppHandler::render`) et `simple.rs`
|
||||||
> et `simple.rs` (API `AppBuilder`, sans `winit`/`wgpu`) déclare un quad rendu automatiquement.
|
> (API `AppBuilder`, sans `winit`/`wgpu`) déclare un quad rendu automatiquement. Les étapes suivantes
|
||||||
> Le même jour (Étape 3 + 4, 2026-09-16) l'**infrastructure 3D** est en place : bind groups uniformes
|
> ont ensuite : posé l'infrastructure 3D (bind groups uniformes frame+object partagés, caméra active,
|
||||||
> partagés (frame + object), caméra active dans la `Scene` (`Scene::set_camera`/`camera()`) écrite dans
|
> matrices monde par entité — Étapes 3+4, 2026-09-16) ; atteint le **MVP 3D Phong** (Étape 5,
|
||||||
> le buffer frame chaque frame, matrices monde par entité. **Étape 5 (2026-09-17) : MVP 3D atteint** —
|
> 2026-09-17 : l'exemple `cube` ; le 2D plat = variante **unlit** de `standard` via
|
||||||
> l'exemple `cube` rend un cube unitaire éclairé (Phong) en rotation via `App::render_scene` ; le
|
> `Renderer::set_unlit`) ; rattaché le `PipelineCache` à la `Scene` et fait référencer son `Material`
|
||||||
> shader `basic` est supprimé, le 2D plat devient la **variante unlit** de `standard`
|
> par chaque `Mesh` (Étape 7) ; donné à `Mesh` une source de vérité **CPU partagée**
|
||||||
> (`Renderer::set_unlit` / `app.renderer_mut().set_unlit(true)`). L'**Étape 7 (2026-09-17)** a rattaché
|
> (`geometry: Arc<Geometry>`, Étape 8) ; activé un **depth buffer** sur toutes les passes (Étape 9) ;
|
||||||
> le `PipelineCache` à la `Scene` et fait référencer son `Material` par chaque `Mesh`. L'**Étape 8
|
> et ajouté les **textures diffuses** (Étape 10, 2026-09-18 : `resources::Texture` + bind group @2 +
|
||||||
> (2026-09-18)** a donné à `Mesh` une source de vérité **CPU partagée** (`geometry: Arc<Geometry>`) :
|
> `Material.texture`).
|
||||||
> `Scene::create_mesh(id, Geometry, material)` déclare les meshes depuis une `Geometry` (avec couleurs),
|
|
||||||
> `Mesh::from_geometry` dérive ses buffers GPU, et les exemples cube/simple/manual utilisent `Geometry`.
|
|
||||||
|
|
||||||
## Phase 1 : Finalisation et Nettoyage de l'Existant (Priorité Absolue)
|
## Phase 1 : Finalisation et Nettoyage de l'Existant (Priorité Absolue)
|
||||||
|
|
||||||
@@ -82,8 +80,9 @@ Une fois la plomberie encapsulée, nous devons rendre l'assemblage des objets co
|
|||||||
|
|
||||||
Une fois les phases 1 à 3 validées, nous pourrons introduire :
|
Une fois les phases 1 à 3 validées, nous pourrons introduire :
|
||||||
|
|
||||||
- [ ] **Système de Lumières** : Ajout de buffers d'uniformes dans le PipelineCache.
|
- [ ] **Système de Lumières** : Ajout de buffers d'uniformes dans le PipelineCache *(planifié — ROADMAP 4.2, Éclairage avancé)*.
|
||||||
- [ ] **Textures** : Intégration d'un module de chargement d'images et de BindGroups.
|
- [X] **Textures** : Intégration d'un module de chargement d'images et de BindGroups *(fait 2026-09-18,
|
||||||
|
Étape 10, ROADMAP 4.1 : `resources::Texture`, bind group @2, `Material.texture`)*.
|
||||||
- [X] **Caméras** : Gestion des matrices de projection/vue dans la Scene *(fait 2026-09-16, Étape 4.3 —
|
- [X] **Caméras** : Gestion des matrices de projection/vue dans la Scene *(fait 2026-09-16, Étape 4.3 —
|
||||||
`Scene::set_camera`/`camera()` porte une caméra active ; `render_scene` écrit view/proj/cam_pos réels
|
`Scene::set_camera`/`camera()` porte une caméra active ; `render_scene` écrit view/proj/cam_pos réels
|
||||||
dans le buffer frame chaque frame, aspect calculé depuis la fenêtre)*.
|
dans le buffer frame chaque frame, aspect calculé depuis la fenêtre)*.
|
||||||
@@ -95,22 +94,6 @@ Une fois les phases 1 à 3 validées, nous pourrons introduire :
|
|||||||
exposée via `Frame::view()`, `render()` dessine la scène automatiquement en une passe via
|
exposée via `Frame::view()`, `render()` dessine la scène automatiquement en une passe via
|
||||||
`App::render_scene(frame.view())`, la présentation est faite par `App::run`)
|
`App::render_scene(frame.view())`, la présentation est faite par `App::run`)
|
||||||
- [X] Les modules sont-ils bien exposés via `lib.rs` ?
|
- [X] Les modules sont-ils bien exposés via `lib.rs` ?
|
||||||
- [X] `pollster` est-il uniquement en dev-dependencies ? — **obsolète** : depuis la migration
|
- [X] `pollster` est-il isolé de l'utilisateur final ? — résolu : depuis winit 0.30 (2026-09-16),
|
||||||
winit 0.30 (2026-09-16), `pollster` est en `dependencies` de la lib (le `block_on` d'init GPU
|
`pollster` est en `dependencies` de la lib ; le `block_on` de l'init GPU est appelé une seule fois
|
||||||
est désormais appelé dans le code de la lib, `app.rs`, cf. note pour mémoire ci-dessous).
|
dans `lib/src/app.rs` (`resumed()`). Les exemples compilent sans le connaître (crates séparées).
|
||||||
|
|
||||||
## Note pour mémoire : couplage au runtime async (pollster)
|
|
||||||
|
|
||||||
Depuis la migration winit 0.30, la lib embarque un runtime async pour l'init GPU. Le point de
|
|
||||||
couplage actuel est **unique** : `pollster::block_on(Context::new(...))` dans `lib/src/app.rs`
|
|
||||||
(`resumed()`), plus le macro `#[pollster::main]` dans les exemples (crates séparées, hors lib).
|
|
||||||
|
|
||||||
À ce stade (un seul appel), **on ne crée volontairement PAS d'abstraction** : ce serait du
|
|
||||||
sur-engineering pour un seul point d'appel. Mais si la lib acquiert d'autres appels async
|
|
||||||
(chargements / uploads GPU, etc.), il faudra isoler le runtime derrière un **module-pivot unique**
|
|
||||||
(`lib/src/exec.rs`, une fonction `block_on`), seul fichier à modifier pour basculer de pollster
|
|
||||||
vers tokio/futures-executor — le reste du code appelant `crate::exec::block_on(...)`.
|
|
||||||
|
|
||||||
Rappel : pollster et tokio sont des runtimes indépendants qui coexistent sans conflit dans un
|
|
||||||
même binaire ; la seule contre-indication est de faire un `pollster::block_on` **à l'intérieur**
|
|
||||||
d'un contexte async tokio (blocage imbriqué / deadlock possible).
|
|
||||||
|
|||||||
+10
-25
@@ -66,16 +66,9 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
sur `Geometry` (8.5).
|
sur `Geometry` (8.5).
|
||||||
- [x] Ajouter un mesh de test (cube unitaire) en exemple — **fait** (helper `cube_geometry` dans l'exemple `cube`, Étape 5, 2026-09-17)
|
- [x] Ajouter un mesh de test (cube unitaire) en exemple — **fait** (helper `cube_geometry` dans l'exemple `cube`, Étape 5, 2026-09-17)
|
||||||
|
|
||||||
> **Note (2026-09-17, DRAFT Étape 7)** : le volet *matériau* de `Mesh` a été fait en Étape 7 :
|
> **État (2026-09-18)** : `Mesh` porte son matériau (`mesh.material: Option<Arc<Material>>`, Étape 7) et
|
||||||
> `Mesh.material: Option<Arc<Material>>` (cf. PLAN Phase 2, gestion des matériaux), indépendant de
|
> une source de vérité CPU partagée (`geometry: Arc<Geometry>`, Étape 8). `Mesh` ne porte **pas** de
|
||||||
> la structure `Geometry`.
|
> `transform` : un même mesh est partagé par plusieurs entités ; le `transform` vit sur `Entity`.
|
||||||
>
|
|
||||||
> **Décision **D3** (2026-09-18, DRAFT Étape 8)** : le ROADMAP listait `transform: Transform` sur `Mesh`.
|
|
||||||
> **Déviation validée : `transform` reste sur `Entity` et n'est PAS ajouté à `Mesh`.** Un mesh est
|
|
||||||
> **partagé** par plusieurs entités à des transforms différents (modèle instancé, Étape 4/7) : un
|
|
||||||
> `transform` unique sur `Mesh` casserait ce modèle. L'Étape 8 met donc en œuvre le refactor de
|
|
||||||
> *stockage CPU* (`Mesh.geometry: Arc<Geometry>` + buffers dérivés) **sans** le champ `transform`.
|
|
||||||
> *(Implémenté 2026-09-18.)*
|
|
||||||
|
|
||||||
### 1.3 Shader Phong Minimal
|
### 1.3 Shader Phong Minimal
|
||||||
- [x] Créer `standard_shader.wgsl` (Étape 2, 2026-09-16) :
|
- [x] Créer `standard_shader.wgsl` (Étape 2, 2026-09-16) :
|
||||||
@@ -98,22 +91,15 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 2️⃣ — Système de Ressources complet
|
## Phase 2️⃣ — Scène enrichie
|
||||||
|
|
||||||
**Objectif** : Étoffer la Scene avec tous les types de ressources.
|
**Objectif** : Étoffer la `Scene` au-delà du MVP.
|
||||||
|
|
||||||
### 2.1 Arènes complètes
|
> Les ressources sont, pour le MVP, identifiées par **String IDs** (décision actée — voir Notes de
|
||||||
- [ ] `SlotMap<MaterialId, Material>`
|
> Décision). Une migration vers des **handles typés** (slotmap générationnel) reste planifiée quand
|
||||||
- [ ] `SlotMap<TextureId, Texture>` (struct de base)
|
> l'éviction/les performances le justifieront (voir 1.4, « reporté »).
|
||||||
- [ ] `SlotMap<LightId, Light>` (struct de base)
|
|
||||||
- [ ] `SlotMap<EntityId, Entity>` pour les entités de la scène
|
|
||||||
|
|
||||||
### 2.2 Entités & Hiérarchie
|
### 2.1 Camera dans la Scene
|
||||||
- [ ] 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)
|
- [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)`)
|
- [ ] 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)
|
- [ ] Exposer une caméra orbitale contrôlable (exemple final, Phase 5)
|
||||||
@@ -152,8 +138,8 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
- [x] `Material` supporte une texture diffuse *(Étape 10 : Material.texture + texture_bind_group, placeholder si None)*
|
- [x] `Material` supporte une texture diffuse *(Étape 10 : Material.texture + texture_bind_group, placeholder si None)*
|
||||||
|
|
||||||
### 4.2 Éclairage avancé
|
### 4.2 Éclairage avancé
|
||||||
|
- [x] Lumières hémisphériques *(déjà dans le `standard_shader` : mélange hémisphérique, Étape 2)*
|
||||||
- [ ] Support multi-lumières (directionnelles, ponctuelles)
|
- [ ] Support multi-lumières (directionnelles, ponctuelles)
|
||||||
- [ ] Lumières hémisphériques
|
|
||||||
- [ ] Shadows (optionnel)
|
- [ ] Shadows (optionnel)
|
||||||
|
|
||||||
### 4.3 Optimisations
|
### 4.3 Optimisations
|
||||||
@@ -188,7 +174,6 @@ generated: { by: human:jerome, at: 2026-07-31T00:00:00Z }
|
|||||||
| Décision | Raison |
|
| Décision | Raison |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| **Normals dès Phase 1** | Nécessaires pour le shader Phong ; sans elles, pas d'éclairage |
|
| **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 |
|
| **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 |
|
| **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 |
|
| **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 |
|
||||||
|
|||||||
Reference in New Issue
Block a user