examples: apply real texture assets to multi-mesh examples

- meshes/cube: procedural checkerboard -> uv_texture.jpg (8x8 UV grid)
- meshes/pbr: floor -> ground.jpeg, bump cube -> cave.jpg + caveNormal.jpg
  (normal map pre-encoded via sRGB OETF to cancel the GPU sRGB decode)
- lights/shadow: ground -> ground.jpeg, cube -> uv_texture.jpg
- effects/demo: ground -> ground.jpeg, cube -> uv_texture.jpg
- effects/fog: ground -> ground.jpeg (tiled 80x80), cubes -> stonewall.jpg
- effects/dof: ground -> ground.jpeg, cubes -> uv_texture.jpg
- cameras/culling: shared cube mesh -> uv_texture.jpg
- add lib/examples/assets/textures/ (19 assets, 6.5 MB)
- document assets + usage in examples READMEs, docs/user/examples.md,
  docs/user/meshes/materials.md (CARGO_MANIFEST_DIR pattern, sRGB caveat)
This commit is contained in:
Jérôme Bousquié
2026-09-26 10:49:13 +02:00
parent fecfdcd2d2
commit e5f3636b42
32 changed files with 341 additions and 104 deletions
+39 -5
View File
@@ -25,9 +25,42 @@ Examples gated behind a Cargo feature need the feature too:
cargo run -p wsg-lib --example import --features import-obj
```
All examples are **self-contained**: procedural textures, hard-coded geometries,
no on-disk assets. All use the declarative API (`AppBuilder` + `AppHandler`)
except `manual`, which demonstrates the low-level workflow instead.
All examples are **self-contained**: hard-coded geometries, and textures that are
either procedural or shipped in [`assets/textures/`](assets/textures/). All use the
declarative API (`AppBuilder` + `AppHandler`) except `manual`, which demonstrates
the low-level workflow instead.
## Texture assets
A few examples (the multi-mesh / multi-effect ones) use real image files from
`assets/textures/`, loaded with `Texture::from_file`. The paths are resolved
against `CARGO_MANIFEST_DIR` at compile time, so the examples work from **any
working directory**:
```rust
const TEXTURES: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/assets/textures");
Texture::from_file(&device, &queue, "label", &format!("{TEXTURES}/ground.jpeg"))
```
Assets used by the examples:
| Asset | Size | Used by | Role |
|-------|------|---------|------|
| `uv_texture.jpg` | 437×438 | `cube`, `demo`, `shadow`, `dof`, `culling` | 8×8 UV atlas visualization (labelled cells + corner coordinates) — makes UV mapping and culling decisions explicit |
| `ground.jpeg` | 512×512 | `demo`, `pbr`, `shadow`, `fog`, `dof` | Seamless ground albedo, tiled via the `Repeat` sampler |
| `stonewall.jpg` | 300×225 | `fog` | Distinctive cube texture — the fog falloff reads clearly on it |
| `cave.jpg` + `caveNormal.jpg` | 600×450 | `pbr` | Albedo + normal-map pair for the PBR normal-mapping demo |
The remaining assets in the folder (`rock.jpg`, `seamlessRoad.jpg`, `stalag.jpg` /
`stalagNormal.jpg`, `stars1.jpg`, sprite/heightmap PNGs, …) are available for
experiments. Two notes:
- `Texture` uploads to `Rgba8UnormSrgb` — correct for **albedo** maps (the GPU
sRGB-decodes on sample). A **normal map** is linear data, so `pbr` pre-encodes
its channels with the sRGB OETF before upload (`load_normal_map`): the GPU
decode then restores the original values (EOTF∘OETF = identity).
- The texture sampler is `Linear` + `Repeat`, so any texture tiles automatically
when UVs exceed [0,1] (the 80×80 fog floor uses this to tile `ground.jpeg`).
> **Where do the files live?** Examples live in subfolders
> (`examples/<folder>/<name>.rs`). Cargo only auto-discovers top-level
@@ -56,6 +89,7 @@ except `manual`, which demonstrates the low-level workflow instead.
name = "my_example"
path = "examples/<folder>/my_example.rs"
```
3. Keep it **self-contained**: procedural textures, hard-coded geometries, no
external assets.
3. Keep it **self-contained**: hard-coded geometries; textures are procedural
or come from `assets/textures/` (resolved via `CARGO_MANIFEST_DIR`, see
*Texture assets* above).
4. Document it in the folder's `README.md` (and in `docs/user/examples.md`).