e5f3636b42
- 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)
124 lines
4.7 KiB
Markdown
124 lines
4.7 KiB
Markdown
# Meshes, Materials & Import
|
||
|
||
Examples covering **geometry and materials**: the minimal workflow, the 3D MVP,
|
||
PBR shading, file import, and the low-level (non-`App`) workflow.
|
||
|
||
| Example | Run command | What it shows |
|
||
|---------|-------------|---------------|
|
||
| `simple` | `cargo run -p wsg-lib --example simple` | The minimal declarative workflow: a flat two-tone quad, **unlit**, rendered automatically |
|
||
| `cube` | `cargo run -p wsg-lib --example cube` | The 3D MVP: a textured (`uv_texture.jpg` UV atlas) cube, lit (directional + point + spot), spinning |
|
||
| `pbr` | `cargo run -p wsg-lib --example pbr` | PBR metallic/roughness + normal mapping (real `cave.jpg` albedo + `caveNormal.jpg`) |
|
||
| `import` | `cargo run -p wsg-lib --example import --features import-obj` | OBJ file import (non-graphical, prints stats to stdout) |
|
||
| `manual` | `cargo run -p wsg-lib --example manual` | The **advanced** workflow: `Context`/`Renderer`/`PipelineCache` driven by hand, without the `App` facade |
|
||
|
||
> All commands run from the repo root. The `import` example additionally
|
||
> requires the `import-obj` Cargo feature.
|
||
|
||
---
|
||
|
||
## `simple` — Minimal Declarative Workflow
|
||
|
||
The "15 lines, no wgpu" model: `AppBuilder` creates the window + GPU, and
|
||
`App::run` drives the update → render → present loop. The scene renders
|
||
**automatically** — the default `AppHandler::render` calls
|
||
`app.render_scene(frame.view())`.
|
||
|
||
The mesh is a flat two-tone quad declared from a `Geometry` (per-vertex
|
||
positions + colors) and drawn with the `standard` shader in **unlit** mode
|
||
(`renderer.set_unlit(true)`): flat 2D is a special case of 3D, one pipeline for all.
|
||
|
||
```sh
|
||
cargo run -p wsg-lib --example simple
|
||
```
|
||
|
||
No keys — static render.
|
||
|
||
---
|
||
|
||
## `cube` — The 3D MVP
|
||
|
||
A lit unit cube that rotates, **textured** with the `uv_texture.jpg` asset — an
|
||
8×8 UV atlas visualization (labelled cells + corner coordinates) that makes
|
||
exactly where each face's UVs land visible. The texture is loaded from
|
||
`assets/textures/` via `Texture::from_file` (path resolved against
|
||
`CARGO_MANIFEST_DIR`), registered by id (`add_texture`) and bound through
|
||
`add_material_texture` (diffuse path, bind group `@group(2)`). Follows the
|
||
declarative workflow (like `simple`): `AppBuilder` + automatic scene, **no wgpu
|
||
import**; the default camera at (0, 0, 3) frames the cube, and `update()`
|
||
rotates the entity via `set_entity_transform` each frame.
|
||
|
||
```sh
|
||
cargo run -p wsg-lib --example cube
|
||
```
|
||
|
||
No keys — the cube spins on its own.
|
||
|
||
---
|
||
|
||
## `pbr` — PBR Metallic/Roughness + Normal Mapping
|
||
|
||
Demonstrates the Cook-Torrance PBR workflow: GGX distribution + Smith geometry +
|
||
Schlick Fresnel + hemispheric IBL + normal mapping.
|
||
|
||
```sh
|
||
cargo run -p wsg-lib --example pbr
|
||
```
|
||
|
||
| Key | Action |
|
||
|-----|--------|
|
||
| Drag (LMB) | Orbit camera |
|
||
| Wheel | Zoom |
|
||
| `R` | Reset camera |
|
||
|
||
Scene: 6 PBR materials (mirror metal, smooth plastic, rusty metal, ceramic,
|
||
cave, textured floor). The floor is a 20×20 plane with the `ground.jpeg`
|
||
albedo; the cave cube pairs `cave.jpg` (albedo) with `caveNormal.jpg`
|
||
(normal map, pre-encoded sRGB before upload — see the *Texture assets* section
|
||
in the parent README) and shows real surface detail under the light.
|
||
|
||
---
|
||
|
||
## `import` — OBJ File Import
|
||
|
||
**Non-graphical** example: parses a `.obj` file and prints statistics
|
||
(vertex count, normals, UVs, indices, bounding box) to stdout.
|
||
|
||
```sh
|
||
# With a file:
|
||
cargo run -p wsg-lib --example import --features import-obj -- /path/to/model.obj
|
||
|
||
# Without argument (demo triangle):
|
||
cargo run -p wsg-lib --example import --features import-obj
|
||
```
|
||
|
||
No keys — runs and exits.
|
||
|
||
---
|
||
|
||
## `manual` — Low-level Workflow (no `App` facade)
|
||
|
||
Demonstrates the API **without** the `App` facade: direct use of `Context`,
|
||
`Renderer`, `PipelineCache`, `Mesh`, `Material`. Renders a colored quad (unlit).
|
||
|
||
Useful for understanding what the `App` facade encapsulates:
|
||
|
||
- `Context` (*Manager* layer): GPU lifecycle — `Instance`/`Surface`/`Adapter`/
|
||
`Device`/`Queue`, `configure()` for the swapchain, per-frame surface texture.
|
||
- `Renderer` (*Executor* layer): `render(view, mesh, material)` = one object per
|
||
submission; `present(frame)`.
|
||
- `PipelineCache`: `register_shader(id, path)` then `Material::new(format, id, &mut cache)`.
|
||
|
||
The window and GPU are created in winit 0.30's `resumed()` callback
|
||
(`run_app` + `ApplicationHandler`). The two-layer architecture is detailed in
|
||
[`docs/tech/ARCHI_APP.md`](../../../docs/tech/ARCHI_APP.md) and
|
||
[`FRAME_LOOP.md`](../../../docs/tech/FRAME_LOOP.md).
|
||
|
||
```sh
|
||
cargo run -p wsg-lib --example manual
|
||
```
|
||
|
||
No keys — static render (unlit quad, 4 colors).
|
||
|
||
> **Tip**: start with the declarative workflow. The manual workflow doesn't
|
||
> render more pixels — it gives more control over command encoding.
|