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
+6 -4
View File
@@ -4,7 +4,7 @@ Examples where the **camera** drives what gets rendered.
| Example | Run command | What it shows |
|---------|-------------|---------------|
| `culling` | `cargo run -p wsg-lib --example culling` | GPU-driven frustum culling: a 15×15 grid of cubes, off-frustum objects skipped |
| `culling` | `cargo run -p wsg-lib --example culling` | GPU-driven frustum culling: a 15×15 grid of UV-atlas cubes, off-frustum objects skipped |
> All commands run from the repo root.
@@ -16,9 +16,11 @@ objects changes — with **zero CPU cost** (the GPU decides in a compute pass).
## `culling` — GPU Frustum Culling
A grid of **15×15 = 225 cubes** is placed on a large floor. The GPU-driven
culling (compute shader) determines which cubes are visible in the camera
frustum and zeros their indirect draw args — **zero CPU cost**.
A grid of **15×15 = 225 cubes** is placed on a large floor. The shared cube
mesh is textured with the `uv_texture.jpg` atlas — the colourful labelled
cells make it obvious exactly which cubes the GPU draws and which it culls.
The GPU-driven culling (compute shader) determines which cubes are visible in
the camera frustum and zeros their indirect draw args — **zero CPU cost**.
```sh
cargo run -p wsg-lib --example culling
+23 -2
View File
@@ -39,9 +39,13 @@ use wsg_lib::app::AppBuilder;
use wsg_lib::camera::CameraController;
use wsg_lib::core::Transform;
use wsg_lib::mesh::{cube, plane};
use wsg_lib::resources::Texture;
use wsg_lib::AppHandler;
use wsg_lib::utils::WsgError;
/// Texture asset directory, resolved against the crate root so the example works from any CWD.
const TEXTURES: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/examples/assets/textures");
/// Grid dimensions (15×15 = 225 cubes, fits within MAX_ENTITIES=256).
const GRID: usize = 15;
/// Spacing between cubes (world units).
@@ -67,9 +71,26 @@ impl AppHandler for CullingDemo {
.unwrap();
app.scene.add_entity("ground", "ground_mesh").unwrap();
// One shared cube mesh (all entities reference the same GPU buffers).
// One shared cube mesh (all entities reference the same GPU buffers), textured with
// the uv_texture.jpg atlas — the colourful labelled cells make it obvious exactly
// which cubes the GPU draws and which it culls.
let (device, queue) = {
let ctx = app.context();
(ctx.device.clone(), ctx.queue.clone())
};
let uv_tex = Texture::from_file(
&device,
&queue,
"uv_atlas",
&format!("{TEXTURES}/uv_texture.jpg"),
)
.unwrap();
app.scene.add_texture("uv_texture", uv_tex).unwrap();
app.scene
.create_mesh("cube_mesh", cube(0.5), None)
.add_material_texture("cube_mat", "standard", "uv_texture")
.unwrap();
app.scene
.create_mesh("cube_mesh", cube(0.5), Some("cube_mat"))
.unwrap();
// Place the grid of cubes.