docs(plan): unify on a single pipeline layout (2D as degenerate 3D)

This commit is contained in:
Jérôme Bousquié
2026-09-16 12:06:56 +02:00
parent f81144918a
commit 14e18cda06
+18 -12
View File
@@ -47,10 +47,13 @@ toucher au rendu (pure façade de données, validable par compilation).
- `@group(1) @binding(0)` : `ObjectUniform { model: mat4 }` - `@group(1) @binding(0)` : `ObjectUniform { model: mat4 }`
- `vs_main` : `clip_position = proj * view * model * vec4(position,1)` ; passe `normal`/`color` en espace monde. - `vs_main` : `clip_position = proj * view * model * vec4(position,1)` ; passe `normal`/`color` en espace monde.
- `fs_main` : éclairage hémisphérique (ambient) + diffuse directionnel (max(dot(N,L),0)), sortie `vec4(color*light, 1)`. - `fs_main` : éclairage hémisphérique (ambient) + diffuse directionnel (max(dot(N,L),0)), sortie `vec4(color*light, 1)`.
- **Mode unlit** : un flag dans `FrameUniforms` (ou `light_color` nul) **neutralise la directionnelle** → couleur
plate. Ainsi « 2D » = `standard` non-éclairé, **cas particulier de la 3D** (décision actée).
- [ ] 2.2 **Constantes** : ajouter `STANDARD_SHADER_PATH = "assets/shaders/standard_shader.wgsl"` et - [ ] 2.2 **Constantes** : ajouter `STANDARD_SHADER_PATH = "assets/shaders/standard_shader.wgsl"` et
`STANDARD_SHADER: &str = include_str!("../shaders/standard_shader.wgsl")` dans `lib/src/utils/conf.rs`. `STANDARD_SHADER: &str = include_str!("../shaders/standard_shader.wgsl")` dans `lib/src/utils/conf.rs`.
- [ ] 2.3 **Corriger le contrat du `basic_shader.wgsl`** (défaut latente) : aligner ses `@location` sur le - [ ] 2.3 **Migrer `basic` vers le mode unlit de `standard`** (défaut latente réglée) : plus de pipeline au
`VertexBufferLayout` (position/normal/uv/color) pour que le rendu plat soit cohérent. **layout vide séparé**. Le rendu plat = `standard` non-éclairé (identité/ortho + ambiance) sous le **même
layout uniformisé**. Le fallback embarqué (`BASIC_SHADER`) devient la variante unlit de `standard`.
- [ ] **Validation** : nouveau `shaders/mod.rs` si include_str le requiert ; `cargo check` OK (le shader n'est - [ ] **Validation** : nouveau `shaders/mod.rs` si include_str le requiert ; `cargo check` OK (le shader n'est
pas encore compilé par un pipeline tant que l'Étape 3 ne le charge pas). pas encore compilé par un pipeline tant que l'Étape 3 ne le charge pas).
@@ -65,8 +68,9 @@ toucher au rendu (pure façade de données, validable par compilation).
- [ ] 3.2 **Bind group layouts** : dans `build_pipeline`, créer 2 `BindGroupLayout` - [ ] 3.2 **Bind group layouts** : dans `build_pipeline`, créer 2 `BindGroupLayout`
(frame @0 + object @1, chacun avec un buffer uniform `Vertex`/`Fragment`/`Vertex|Fragment` selon usage) et les (frame @0 + object @1, chacun avec un buffer uniform `Vertex`/`Fragment`/`Vertex|Fragment` selon usage) et les
passer dans `PipelineLayoutDescriptor.bind_group_layouts`. `immediate_size` reste 0 (pas de `var<immediate>`). passer dans `PipelineLayoutDescriptor.bind_group_layouts`. `immediate_size` reste 0 (pas de `var<immediate>`).
- [ ] 3.3 **Compat** : le chemin `basic` (sans uniforms) continue de fonctionner soit via le même layout (bind - [ ] 3.3 **Acté : un seul layout pour tous** (option A). `build_pipeline` attache **toujours** les 2 bind groups
groups optionnels), soit en gardant le pipeline sans layout pour les mathériaux non-3D. **Décision à acter.** (frame @0 + object @1). Plus de famille `basic` au layout vide : tout matériau partage le même layout
uniformisé. `manual`/quad plat migrent (Étape 5).
- [ ] **Validation** : `cargo check` 0 warning ; `cargo doc` 0 warning (types documentés, `missing_docs` actif). - [ ] **Validation** : `cargo check` 0 warning ; `cargo doc` 0 warning (types documentés, `missing_docs` actif).
## Étape 4 — Rendu 3D dans le `Renderer` ## Étape 4 — Rendu 3D dans le `Renderer`
@@ -80,19 +84,21 @@ toucher au rendu (pure façade de données, validable par compilation).
car `render_scene(&self, &Scene)` est immuable. Chaque frame : écrire `ObjectUniform.world = entity.transform.to_matrix()` + `set_bind_group(1, ...)`. car `render_scene(&self, &Scene)` est immuable. Chaque frame : écrire `ObjectUniform.world = entity.transform.to_matrix()` + `set_bind_group(1, ...)`.
- [ ] 4.3 **Caméra active** : ajouter `scene.set_active_camera(Camera)` / `scene.active_camera() -> Option<&Camera>`. - [ ] 4.3 **Caméra active** : ajouter `scene.set_active_camera(Camera)` / `scene.active_camera() -> Option<&Camera>`.
Calcul du `proj` avec l'aspect de la fenêtre (`window.inner_size()` accessible via `App.window`). Calcul du `proj` avec l'aspect de la fenêtre (`window.inner_size()` accessible via `App.window`).
- [ ] 4.4 **`draw_entity` étendu** : `set_bind_group(0, frame_bg)` + `set_bind_group(1, object_bg)` avant le draw. - [ ] 4.4 **`draw_entity` étendu** : `set_bind_group(0, frame_bg)` + `set_bind_group(1, object_bg)` avant le draw,
Le chemin bas-niveau `Renderer::render` peut prendre un `Transform`/uniform optionnel (ou rester non-éclairé). pour **tout** matériau (layout unique). Le chemin bas-niveau `Renderer::render` pose aussi les 2 bind groups
(frame partagé + object du mesh appelant).
- [ ] **Validation** : `cargo check` 0 warning ; exécution `simple` (sans panique, boucle active) ; - [ ] **Validation** : `cargo check` 0 warning ; exécution `simple` (sans panique, boucle active) ;
`manual` non-régressif (chemin bas-niveau). `manual` non-régressif (chemin bas-niveau).
## Étape 5 — Exemple 3D (cube éclairé) ## Étape 5 — Exemple 3D (cube éclairé)
**But** : démontrer l'objectif MVP à l'écran sans régression du modèle déclaratif plat. **But** : démontrer l'objectif MVP à l'écran et **migrer** les exemples sur le pipeline unifié.
- [ ] 5.1 **Nouvel exemple `lib/examples/cube.rs`** : cube unitaire (positions + normales), matériau - [ ] 5.1 **Nouvel exemple `lib/examples/cube.rs`** : cube unitaire (positions + normales), matériau
`standard`, `Transform` non-identique, camera + lumière directionnelle, rotation dans `AppHandler::update`. `standard` éclairé, `Transform` non-identique, camera + lumière directionnelle, rotation dans `AppHandler::update`.
Toujours via `AppBuilder`/scène automatique, **sans importer wgpu** (comme `simple`). Toujours via `AppBuilder`/scène automatique, **sans importer wgpu** (comme `simple`).
- [ ] 5.2 Garder `simple.rs` (quad plat) et `manual.rs` (bas niveau) inchangés comme références. - [ ] 5.2 **Migrer `simple.rs`** (quad plat → `standard` **unlit**, transform identité) et **`manual.rs`** (bas niveau
→ bind groups frame+object posés, unlit). `basic` disparaît comme famille séparée.
- [ ] **Validation** : compile + tourne sans panique ; rotation/éclairage visibles (à confirmer sur GPU/fenêtre). - [ ] **Validation** : compile + tourne sans panique ; rotation/éclairage visibles (à confirmer sur GPU/fenêtre).
## Étape 6 — Validation globale & docs ## Étape 6 — Validation globale & docs
@@ -111,6 +117,6 @@ toucher au rendu (pure façade de données, validable par compilation).
| Schéma uniforms | 2 bind groups : frame partagé (@0) + object par entité (@1) | Simple, extensible ; évite `var<immediate>` (limites de taille, hazard) | | Schéma uniforms | 2 bind groups : frame partagé (@0) + object par entité (@1) | Simple, extensible ; évite `var<immediate>` (limites de taille, hazard) |
| Cache object buffer | `RefCell<HashMap<label, (Buffer, BindGroup)>>` dans `Renderer` | `render_scene(&self)` immuable ; MVP petit nombre d'entités | | Cache object buffer | `RefCell<HashMap<label, (Buffer, BindGroup)>>` dans `Renderer` | `render_scene(&self)` immuable ; MVP petit nombre d'entités |
| Transform dans l'entité | `Entity { mesh_id, material_id, transform }` + `add_entity_with_transform` | `add_entity` garde sa signature (transform identité) | | Transform dans l'entité | `Entity { mesh_id, material_id, transform }` + `add_entity_with_transform` | `add_entity` garde sa signature (transform identité) |
| Layout pipeline non-3D | (à trancher — cf. 3.3) : layout commun avec bind groups optionnels OU pipeline `basic` distinct | À arbitrer selon la charge de travail | | Layout pipeline | **Acté : un seul layout pour tous** (frame @0 + object @1) ; `basic` unlit = variante de `standard` | 2D = cas particulier 3D (décision utilisateur) ; supprime la fourchette à deux layouts pour toujours |
| Exemple démo | Nouvel exemple `cube.rs` (ne pas réécrire `simple.rs`) | `simple` reste le modèle déclaratif minimal | | Exemple démo | Nouvel exemple `cube.rs` (éclairé) ; `simple.rs` et `manual.rs` **migrés** vers le pipeline unifié (unlit) | Démontre le 3D sans dédoubler ; cohérent avec « un seul layout pour tous » |
| Correction `basic_shader.wgsl` | Aligner les `@location` sur le vrai layout | Supprime une incohérence latente avant tout travail Phong | | Correction `basic_shader.wgsl` | **Supprimer** `basic` comme pipeline séparé ; le quad plat devient `standard` unlit | 2D ⊂ 3D : pas de famille de pipeline dédiée |