feat(renderer): uniform bind groups infrastructure (Étape 3 + 4.1/4.2/4.4)
Étape 3 (infrastructure uniforms) + le câblage minimal d'Étape 4 pour garder les exemples exécutables (wgpu requiert que tous les bind groups du layout pipeline soient posés au draw) : - resources/uniform.rs : types bytemuck Pod FrameUniforms (192 B) et ObjectUniform (64 B), alignés 16 octets sans padding; offsets vérifiés par un test unitaire contre le contrat du shader. glam feature bytemuck activé. - pipeline_cache: create_uniform_bind_group_layouts() expose les 2 layouts (frame @0 Vertex|Fragment + object @1 Vertex); build_pipeline les attache à TOUT pipeline (un seul layout pour tous, décision actée). - Renderer: alloue le buffer frame partagé + BindGroup(0) (défaut identité, mode lit) et un object identité partagé pour le chemin bas-niveau; cache RefCell<HashMap<label,(buffer,bindgroup)>> par entité, model réécrit chaque frame depuis transform.to_matrix(); draw_entity pose groupes 0+1. 4.3 (caméra active + aspect) non implémenté: simple/manual restent exécutables car basic ignore ces uniforms. Documentation DRAFT mise à jour. Validation: check workspace+examples 0 warning, doc 0 warning, test (Pod+wgsl) OK, fmt propre.
This commit is contained in:
+26
-23
@@ -70,34 +70,37 @@ toucher au rendu (pure façade de données, validable par compilation).
|
||||
|
||||
**But** : permettre aux pipelines de recevoir des uniforms (bind groups) au lieu de `bind_group_layouts: &[]`.
|
||||
|
||||
- [ ] 3.1 **Types bytemuck `Pod`** (nouveau `lib/src/resources/uniform.rs`, ou `math/uniform.rs`) :
|
||||
- `#[repr(C)] #[derive(Pod, Zeroable, Copy, Clone)] FrameUniforms` (voir 2.1)
|
||||
- `#[repr(C)] #[derive(...)] ObjectUniform { model: Mat4 }`
|
||||
- (alignement 16 octets : utiliser `Vec4`/tableaux pour éviter le padding). Exporter via le `mod.rs` concerné.
|
||||
- [ ] 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
|
||||
passer dans `PipelineLayoutDescriptor.bind_group_layouts`. `immediate_size` reste 0 (pas de `var<immediate>`).
|
||||
- [ ] 3.3 **Acté : un seul layout pour tous** (option A). `build_pipeline` attache **toujours** les 2 bind groups
|
||||
(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).
|
||||
- [X] 3.1 **Types bytemuck `Pod`** (nouveau `lib/src/resources/uniform.rs`) : `FrameUniforms` (192 B) et
|
||||
`ObjectUniform` (64 B), `#[repr(C)]`, 16-byte alignés, sans padding — offset vérifiés par un test
|
||||
unitaire contre la table du shader. Exports via `resources/mod.rs`. *(fait — 2026-09-16. Au passage,
|
||||
`glam` feature `bytemuck` activé pour que `Mat4`/`Vec4` implémentent `Pod`/`Zeroable`.)*
|
||||
- [X] 3.2 **Bind group layouts** : nouveau `create_uniform_bind_group_layouts(device)` (dans
|
||||
`pipeline_cache.rs`, exporté) → frame @0 (`Uniform`, `Vertex|Fragment`) + object @1 (`Uniform`, `Vertex`).
|
||||
`build_pipeline` les passe dans le `PipelineLayoutDescriptor`. `immediate_size` reste 0.
|
||||
*(fait — 2026-09-16)*
|
||||
- [X] 3.3 **Acté : un seul layout pour tous** (option A). `build_pipeline` attache **toujours** les 2 bind
|
||||
groups (frame @0 + object @1), même si le shader ne les lit pas (validation wgpu : layout╱bind group).
|
||||
*(fait — 2026-09-16)*
|
||||
- [X] **Validation** : `cargo check --workspace --examples` 0 warning ; `cargo doc --no-deps` 0 warning ;
|
||||
`cargo test` (types Pod + wgsl naga) OK ; `cargo fmt` propre. *(fait — 2026-09-16)*
|
||||
|
||||
## Étape 4 — Rendu 3D dans le `Renderer`
|
||||
|
||||
**But** : `render_scene` applique matrices + éclairage par entité.
|
||||
|
||||
- [ ] 4.1 **Buffers frame partagés** : créer le `wgpu::Buffer` `FrameUniforms` + `BindGroup(0)` dans
|
||||
`Renderer::new` (ou à la 1re frame). Écrire chaque frame : view/proj (caméra active) + lumière.
|
||||
- [ ] 4.2 **Buffers object par entité** : `Renderer` maintient un cache
|
||||
`RefCell<HashMap<String, (wgpu::Buffer, wgpu::BindGroup)>>` clefé par label d'entité (créé à la 1re rencontre),
|
||||
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>`.
|
||||
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,
|
||||
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) ;
|
||||
`manual` non-régressif (chemin bas-niveau).
|
||||
- [X] 4.1 **Buffers frame partagés** : le `Renderer::new` crée le `wgpu::Buffer` `FrameUniforms` + `BindGroup(0)`
|
||||
(défaut : caméra identité + lumière blanche + mode lit). *(fait — 2026-09-16)*
|
||||
- [X] 4.2 **Buffers object par entité** : le `Renderer` maintient un cache
|
||||
`RefCell<HashMap<String,(wgpu::Buffer, wgpu::BindGroup)>>` clefé par label d'entité ; chaque frame il
|
||||
écrit `ObjectUniform.world = entity.transform.to_matrix()` (via `object_bind_group_for`). *(fait — 2026-09-16)*
|
||||
- [ ] 4.3 **Caméra active** : ajouter `scene.set_active_camera(Camera)` / `scene.active_camera() -> Option<&Camera>` ;
|
||||
écrire view/proj (avec aspect de la fenêtre) dans le buffer frame chaque frame. *(non fait — laisse le
|
||||
`FrameUniforms::default()` : simple/manual tournent toujours via `basic` qui ignore ces uniforms)*
|
||||
- [X] 4.4 **`draw_entity` étendu** : pose `set_bind_group(0, frame_bg)` + `set_bind_group(1, object_bg)` avant le
|
||||
draw (groupes requis par le layout unique) ; le chemin bas-niveau `Renderer::render` pose aussi les 2 bind
|
||||
groups (frame partagé + object identité partagé). *(fait — 2026-09-16)*
|
||||
- [ ] **Validation** : `cargo check` 0 warning ; exécution `simple` (sans panique, boucle active). *(une partie :
|
||||
`simple` reste exécutable car `basic` ignore les uniforms ; le rendu 3D réel attend 4.3)*
|
||||
|
||||
## Étape 5 — Exemple 3D (cube éclairé)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user