feat(particles): Étape 28 A — ParticlePool infrastructure (no driver)
Creates the GPU resource layer for particles per ARCHI §3.2/§6, without simulation: the pool owns all buffers/pipeline/bind group but draws nothing (indirect args zeroed → no-op) until a driver is attached (Étape B). New: - resources/particle.rs: Particle (80 B, #[repr(C)], no padding — D19), SIZE/ZERO consts + offset/layout unit tests - shaders/particle_billboard.wgsl: camera-facing billboard, empty vertex layout (quad via vertex_index), instance slot via storage binding compact_index (D17), uv_rect atlas support (D15/D18) - core/particles.rs: ParticlePoolConfig, BlendingMode, ParticleDriver trait (D3), ParticlePool (4 buffers + pipeline + bind group), default disc texture (D11), unit tests Wired: - Scene: SceneGpu keeps queue/sample_count; particle_pools registry + create_particle_pool() (default disc when no texture given) - utils::conf PARTICLE_BILLBOARD_SHADER, module re-exports, prelude - tests/wgsl_validate.rs: particle billboard naga validation (2 entry points) Docs: DRAFT call-site/tree synced with the final code; AGENTS.md test count (138) + wgpu 30 API drift gotcha (contents/DeviceExt/ALPHA_BLENDING, DepthStencilState no Default, NonZero min_binding_size, const Zeroable). cargo test -p wsg-lib: 138 pass (121 lib + 10 wgsl + 7), 0 warnings.
This commit is contained in:
@@ -43,9 +43,10 @@ WGPU doesn't have a native "Context" object — this type groups them together f
|
||||
## Gotchas
|
||||
- Rust 2024 edition is used. Ensure your Rust toolchain supports it (`rustup update`).
|
||||
- wgpu 30.0.0 is pinned in `lib/Cargo.toml`. The comment says "check the latest version" — verify compatibility before upgrading.
|
||||
- Cargo features gate primitives (`prim-*`, `all-prims` is default) and importers (`import-obj`, `import-gltf`); the `import` example is `required-features = ["import-obj"]`. 127 tests exist (`cargo test --workspace`).
|
||||
- Cargo features gate primitives (`prim-*`, `all-prims` is default) and importers (`import-obj`, `import-gltf`); the `import` example is `required-features = ["import-obj"]`. 138 tests exist (`cargo test --workspace`, incl. particle layout + billboard WGSL validation).
|
||||
- The workspace has no `[workspace.dependencies]` section. Dependencies are declared per-crate rather than centrally.
|
||||
- **WGSL `select` argument order** (cost us a day): `select(reject, accept, cond)` returns the **second** arg when `cond` is true — the reverse of HLSL's `select(trueVal, falseVal, cond)`. In `shaders/gpu_driven.wgsl` the cull pass must stay `select(0u, u32(flags.z), visible)` (visible ⇒ full count, culled ⇒ 0). Swapped args silently zero the counts of every visible entity → black window. See the GOTCHA comment at the top of that shader.
|
||||
- **wgpu 30 API drift** (verified this session): `BufferInitDescriptor` has a `contents: &[u8]` field (not `data`) and `create_buffer_init` comes from the `wgpu::util::DeviceExt` trait (import it, as in `mesh.rs`). `BlendState::ALPHA_BLENDING` is the alpha-blend constant (there is no `ALPHA`); `DepthStencilState` has **no** `Default` impl — write `stencil`/`bias` fields explicitly. `min_binding_size` is `Option<NonZero<u64>>`. bytemuck 1.25: `Zeroable::zeroed()` is not `const` (const traits unstable) — use a const literal for `ZERO`-style constants. For layout-offset tests prefer `std::mem::offset_of!` (stable 1.77, no unsafe).
|
||||
- **LOD UV blending: never fold integer-tile jumps, freeze seam twins instead** (cost us a day, 2026-09-23): a UV *seam* is two copies of the same 3-D point on integer-apart UVs (u=0/u=1 columns) — it is NOT a mesh edge, so the decimation must record the weld's refused pairs and **freeze** those twins (any edge touching one is excluded from the PQ). A co-facial edge spanning a whole tile (cone apex v=1 ↔ base v=0) is a *legit* chart span — the chart is bilinear, so the UVs **blend linearly** (fold the integer jump to zero and the apex UV smears down the cone side). And the attribute-aware weld refuses a Δ of *exactly* 0.5 (ambiguous: seam at its widest vs legit half-tile jump — the cone's u=1 column vs the cap-disc chart sits exactly there). See the comments in `geometry.rs` (`welded`, `Collapse::collapse_edge`) and the cone/seam regression tests.
|
||||
|
||||
<!-- lean-ctx -->
|
||||
|
||||
Reference in New Issue
Block a user