réorg doc
This commit is contained in:
+47
-326
@@ -1,340 +1,61 @@
|
||||
# WSG Examples
|
||||
|
||||
Each example is self-contained and demonstrates **one effect or feature** of the library. All use the declarative API (`AppBuilder` + `AppHandler`).
|
||||
The examples are organized into **four category folders**, one per theme. Each
|
||||
folder has its own `README.md` documenting its examples in detail (what they
|
||||
demonstrate, how to run them, keyboard controls, what to observe).
|
||||
|
||||
| Folder | Theme | Examples |
|
||||
|--------|-------|----------|
|
||||
| [meshes/](meshes/README.md) | Geometry, materials, file import, low-level workflow | `simple`, `cube`, `pbr`, `import`, `manual` |
|
||||
| [lights/](lights/README.md) | Light types, shadow mapping, emissive materials | `shadow`, `shadow_test`, `spot_test`, `emissive` |
|
||||
| [cameras/](cameras/README.md) | Camera-driven rendering (frustum culling) | `culling` |
|
||||
| [effects/](effects/README.md) | HDR, tone mapping, post-process, full showcase | `demo`, `bloom`, `hdr`, `msaa`, `fog`, `dof` |
|
||||
|
||||
## Running an example
|
||||
|
||||
Example **names are stable** — from the repo root:
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example <name>
|
||||
```
|
||||
|
||||
| Example | Effect demonstrated |
|
||||
|---------|-------------------|
|
||||
| `demo` | Full showcase (all effects combined) |
|
||||
| `bloom` | Post-process bloom (glow around bright areas) |
|
||||
| `hdr` | HDR + Tone Mapping (ACES) + exposure control |
|
||||
| `emissive` | Emissive materials (increasing intensities 0 → 4.0) |
|
||||
| `shadow` | Shadow mapping (directional shadow) |
|
||||
| `culling` | GPU-driven culling (15×15 grid, off-frustum objects skipped) |
|
||||
| `msaa` | MSAA 4× (multisample anti-aliasing, smooth edges) |
|
||||
| `fog` | Distance fog (3 modes: linear, exp, exp²) |
|
||||
| `dof` | Depth of Field (cinematic bokeh, focus presets) |
|
||||
| `pbr` | PBR metallic/roughness + normal mapping |
|
||||
| `manual` | Low-level workflow (Context + Renderer + PipelineCache) |
|
||||
| `import` | OBJ file import (non-graphical, stdout) |
|
||||
|
||||
---
|
||||
|
||||
## `demo` — Full Showcase
|
||||
|
||||
Combines **all** effects: LOD primitives, procedural textures, lights
|
||||
(directional + point + spot), shadows, HDR/ACES, exposure, emissive, bloom, culling.
|
||||
Examples gated behind a Cargo feature need the feature too:
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example demo
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `1` / `2` / `3` | Presets: front / side / top |
|
||||
| `+` / `-` | Exposure ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposure |
|
||||
|
||||
---
|
||||
|
||||
## `bloom` — Post-process Bloom
|
||||
|
||||
Two emissive spheres (orange intensity 2.0, blue intensity 3.0) produce a visible
|
||||
halo. The cube and floor serve as reference (non-emissive).
|
||||
|
||||
Bloom is a 4-pass GPU pipeline: threshold → blur H → blur V → composite.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example bloom
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `+` / `-` | **Bloom threshold** +0.1 / −0.1 |
|
||||
| `[` / `]` | **Bloom intensity** +0.1 / −0.1 |
|
||||
| `I` / `O` | **Bloom radius** +0.5 / −0.5 |
|
||||
| `E` / `Q` | Exposure ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposure |
|
||||
|
||||
### What to observe
|
||||
|
||||
- **Low threshold** (0.0): the entire image "blooms" (very diffuse effect).
|
||||
- **High threshold** (2.0+): only the bright emissive spheres produce glow.
|
||||
- **Intensity 0.0**: no visible glow (even though the threshold extracts pixels).
|
||||
- **Large radius** (10+): the glow spreads over a large area.
|
||||
|
||||
---
|
||||
|
||||
## `hdr` — HDR + Tone Mapping
|
||||
|
||||
Demonstrates HDR rendering with the ACES Filmic curve. Three objects:
|
||||
|
||||
- **Cube**: normal lighting (no emissive) — LDR reference.
|
||||
- **Bright sphere** (emissive 3.0): without HDR, it would be clamped to white.
|
||||
With ACES, highlights "roll off" smoothly toward white.
|
||||
- **Dark sphere** (emissive 0.3): stays dark even at high exposure.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example hdr
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `E` | **Exposure ×1.3** (brighter) |
|
||||
| `Q` | **Exposure ÷1.3** (darker) |
|
||||
| `0` | Reset exposure to 1.0 |
|
||||
|
||||
### What to observe
|
||||
|
||||
- At exposure 1.0: the bright sphere is white but with detail (ACES rolloff).
|
||||
- At high exposure (E×E×E): the scene brightens, the bright sphere stays white
|
||||
(saturated), but the cube gains detail.
|
||||
- At low exposure (Q×Q): everything darkens, the bright sphere becomes orange
|
||||
(HDR values > 1.0 are compressed).
|
||||
|
||||
> **Note**: the tone mapper is compiled into the pipeline at build time. To compare
|
||||
> ACES vs Reinhard, change `ToneMapper::Aces` → `ToneMapper::Reinhard` in the source.
|
||||
|
||||
---
|
||||
|
||||
## `emissive` — Emissive Materials
|
||||
|
||||
Five spheres in a row with increasing emissive intensities:
|
||||
|
||||
| Sphere | Color | Intensity | Effect |
|
||||
|--------|-------|-----------|--------|
|
||||
| 1 | Gray | 0.0 | No glow (reference) |
|
||||
| 2 | Orange | 0.5 | Slight glow |
|
||||
| 3 | Yellow | 1.0 | Visible glow |
|
||||
| 4 | Green | 2.0 | HDR glow (beyond 1.0) |
|
||||
| 5 | Blue | 4.0 | Intense glow (saturation) |
|
||||
|
||||
With HDR, intensities > 1.0 produce a true "glow" (values exceed
|
||||
[0,1] in linear space). Without HDR, they would be clamped to white.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example emissive
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `E` / `Q` | Exposure ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposure |
|
||||
| `C` | **Cycle emissive multiplier** (1× → 2× → 0.5× → ...) |
|
||||
|
||||
### What to observe
|
||||
|
||||
- Sphere 1 (intensity 0) is simply lit by the directional light.
|
||||
- Spheres 2-5 glow with their own light, independent of scene lighting.
|
||||
- `C` doubles or halves all intensities simultaneously (to see the HDR effect).
|
||||
|
||||
---
|
||||
|
||||
## `shadow` — Shadow Mapping
|
||||
|
||||
Four objects (cube, sphere, cone, cylinder) on a floor, lit by a directional light
|
||||
that casts shadows. Shadow quality is controlled by `ShadowConfig` (map size, anti-acne bias).
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example shadow
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `1` | Front view |
|
||||
| `2` | Side view |
|
||||
| `3` | **Top view** (see shadow shapes clearly) |
|
||||
| `L` | Change light direction (3 presets) |
|
||||
|
||||
### What to observe
|
||||
|
||||
- The cube rotates slowly → its shadow moves on the floor.
|
||||
- The sphere has a smooth shadow/light transition (soft terminator).
|
||||
- The cone produces a distinct triangular shadow.
|
||||
- In top view (`3`), you see the exact shape of projected shadows.
|
||||
- Shadow map size (1024 default) determines resolution:
|
||||
modify `SHADOW_MAP_SIZE` at the top of the file to test 256 (pixelated) or 2048 (sharp).
|
||||
|
||||
---
|
||||
|
||||
## `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**.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example culling
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera (look around) |
|
||||
| Wheel | Zoom in/out |
|
||||
| `R` | Reset (top view) |
|
||||
| `1` | Front view (cubes behind are culled) |
|
||||
| `2` | Side view |
|
||||
| `3` | **Top view** (see the full grid) |
|
||||
|
||||
### What to observe
|
||||
|
||||
- In top view (`3`): the entire grid is visible.
|
||||
- Orbit to 90°: cubes behind the camera **are not drawn** (culled).
|
||||
- Zoom very close: only cubes near the near plane are rendered.
|
||||
- Cubes rotate slowly (staggered phases) → culling is dynamic
|
||||
(a cube can enter/leave the frustum during a frame).
|
||||
|
||||
> **Note**: culling is enabled via `AppBuilder::with_culling(true)`. Changing
|
||||
> it to `false` in the source disables culling (all cubes are always drawn, even off-screen).
|
||||
|
||||
---
|
||||
|
||||
## `msaa` — MSAA 4× (Anti-aliasing)
|
||||
|
||||
Demonstrates multisample anti-aliasing: object edges (cube, sphere)
|
||||
are smooth instead of "stair-stepped". The scene contains a cube (sharp edges),
|
||||
a sphere (curved silhouette), and a small cube near the camera (maximum aliasing).
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example msaa
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `M` | Show sample count |
|
||||
|
||||
### To compare with/without MSAA
|
||||
|
||||
Remove the `.with_msaa(4)` line in the source and recompile: the scene is
|
||||
identical, only the edges differ (stair-stepped vs smooth).
|
||||
|
||||
> **Note**: MSAA is a build-time setting (multisample texture allocation).
|
||||
> It works independently of HDR: with HDR, the MSAA texture is `Rgba16Float`
|
||||
> and resolves into the HDR texture before bloom/TM.
|
||||
|
||||
---
|
||||
|
||||
## `fog` — Distance Fog
|
||||
|
||||
Demonstrates the 3 fog modes: **linear**, **exponential**, **exponential²**.
|
||||
The scene contains a row of cubes receding into the distance and scattered spheres
|
||||
on a large floor plane. Fog blends objects toward a background color,
|
||||
creating the illusion of an infinite world.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example fog --features "all-prims"
|
||||
```
|
||||
|
||||
**Keys**: `1` = linear, `2` = exp, `3` = exp², `4` = off, `R` = reset.
|
||||
|
||||
> Fog is applied in the main fragment shader (after lighting, before tone mapping).
|
||||
> It uses the Euclidean distance from the fragment to the camera.
|
||||
|
||||
---
|
||||
|
||||
## `dof` — Depth of Field (cinematic bokeh)
|
||||
|
||||
Demonstrates depth of field blur: an object at the focus plane stays sharp while
|
||||
foreground and background blur according to their distance from the focus plane.
|
||||
Creates a natural attention effect (cinematic style).
|
||||
|
||||
The scene contains 20 cubes in a row along Z (z=3 to z=-25.5) and 5 spheres to the
|
||||
sides, on a floor plane. Focus presets at 3m / 8m / 15m.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example dof --features "all-prims"
|
||||
```
|
||||
|
||||
**Keys**: `1` = cinematic, `2` = subtle, `3` = focus 3m, `4` = focus 15m, `5` = off, `R` = reset.
|
||||
|
||||
> DoF operates in linear HDR (after bloom, before tone mapping). Two passes:
|
||||
> CoC (depth → per-pixel blur radius) then 12-tap disc blur with variable radius.
|
||||
|
||||
---
|
||||
|
||||
## `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, bump map, matte floor).
|
||||
The bump-map cube shows procedural sin-wave surface detail.
|
||||
|
||||
---
|
||||
|
||||
## `manual` — Low-level Workflow
|
||||
|
||||
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.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example manual
|
||||
```
|
||||
|
||||
No keys — static render (unlit quad, 4 colors).
|
||||
|
||||
---
|
||||
|
||||
## `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.
|
||||
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.
|
||||
|
||||
> **Where do the files live?** Examples live in subfolders
|
||||
> (`examples/<folder>/<name>.rs`). Cargo only auto-discovers top-level
|
||||
> `examples/*.rs`, so every example is declared explicitly in
|
||||
> [`lib/Cargo.toml`](../Cargo.toml) with its `path`. This keeps
|
||||
> `--example <name>` working while allowing the folder organization.
|
||||
|
||||
## Suggested learning path
|
||||
|
||||
1. `simple` — the minimal declarative workflow (flat unlit quad, ~15 lines)
|
||||
2. `cube` — the 3D MVP: a textured, lit, spinning cube
|
||||
3. `pbr` — PBR materials and normal mapping
|
||||
4. `spot_test`, `shadow_test` — isolated light and shadow behavior
|
||||
5. `hdr` → `emissive` → `bloom` — the HDR chain, step by step
|
||||
6. `culling` — GPU-driven frustum culling
|
||||
7. `demo` — everything combined
|
||||
8. `manual` — what the `App` facade actually encapsulates
|
||||
|
||||
## Adding your own example
|
||||
|
||||
1. Create `lib/examples/<folder>/my_example.rs` (pick the matching category;
|
||||
add a new folder + README if needed).
|
||||
2. Declare it in `lib/Cargo.toml` (Cargo won't discover it otherwise):
|
||||
```toml
|
||||
[[example]]
|
||||
name = "my_example"
|
||||
path = "examples/<folder>/my_example.rs"
|
||||
```
|
||||
3. Keep it **self-contained**: procedural textures, hard-coded geometries, no
|
||||
external assets.
|
||||
4. Document it in the folder's `README.md` (and in `docs/user/examples.md`).
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Cameras & Camera-Driven Rendering
|
||||
|
||||
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 |
|
||||
|
||||
> All commands run from the repo root.
|
||||
|
||||
The frustum is defined by the camera's view-projection matrix, so frustum
|
||||
culling is inherently a camera concept: move the camera and the set of drawn
|
||||
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**.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example culling
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera (look around) |
|
||||
| Wheel | Zoom in/out |
|
||||
| `R` | Reset (top view) |
|
||||
| `1` | Front view (cubes behind are culled) |
|
||||
| `2` | Side view |
|
||||
| `3` | **Top view** (see the full grid) |
|
||||
|
||||
### What to observe
|
||||
|
||||
- In top view (`3`): the entire grid is visible.
|
||||
- Orbit to 90°: cubes behind the camera **are not drawn** (culled).
|
||||
- Zoom very close: only cubes near the near plane are rendered.
|
||||
- Cubes rotate slowly (staggered phases) → culling is dynamic (a cube can
|
||||
enter/leave the frustum during a frame).
|
||||
|
||||
> **Note**: culling is enabled via `AppBuilder::with_culling(true)`. Changing
|
||||
> it to `false` in the source disables culling (all cubes are always drawn,
|
||||
> even off-screen).
|
||||
>
|
||||
> The GPU-driven pipeline (compute matrices → culling → indirect draws) is
|
||||
> documented in [`docs/tech/ARCHI_CPU_GPU.md`](../../docs/tech/ARCHI_CPU_GPU.md)
|
||||
> and [`docs/user/gpu-driven.md`](../../docs/user/gpu-driven.md).
|
||||
@@ -0,0 +1,178 @@
|
||||
# Effects: HDR, Post-process & Showcase
|
||||
|
||||
Examples covering **HDR / tone mapping** and **post-process effects**, plus
|
||||
the full showcase that combines everything.
|
||||
|
||||
| Example | Run command | What it shows |
|
||||
|---------|-------------|---------------|
|
||||
| `demo` | `cargo run -p wsg-lib --example demo` | **Full showcase**: 6 LOD primitives, 3 lights, shadows, HDR/ACES, bloom, culling, orbital camera |
|
||||
| `bloom` | `cargo run -p wsg-lib --example bloom` | Post-process bloom (glow around bright areas) |
|
||||
| `hdr` | `cargo run -p wsg-lib --example hdr` | HDR + tone mapping (ACES) + runtime exposure control |
|
||||
| `msaa` | `cargo run -p wsg-lib --example msaa` | MSAA 4× (multisample anti-aliasing, smooth edges) |
|
||||
| `fog` | `cargo run -p wsg-lib --example fog --features "all-prims"` | Distance fog (3 modes: linear, exp, exp²) |
|
||||
| `dof` | `cargo run -p wsg-lib --example dof --features "all-prims"` | Depth of field (cinematic bokeh, focus presets) |
|
||||
|
||||
> All commands run from the repo root. All effects are **opt-in** — a disabled
|
||||
> effect allocates nothing and executes nothing.
|
||||
|
||||
---
|
||||
|
||||
## `demo` — Full Showcase
|
||||
|
||||
Combines **all** effects: LOD primitives, procedural textures, lights
|
||||
(directional + point + spot), shadows, HDR/ACES, exposure, emissive, bloom, culling.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example demo
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `1` / `2` / `3` | Presets: front / side / top |
|
||||
| `+` / `-` | Exposure ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposure |
|
||||
|
||||
---
|
||||
|
||||
## `bloom` — Post-process Bloom
|
||||
|
||||
Two emissive spheres (orange intensity 2.0, blue intensity 3.0) produce a
|
||||
visible halo. The cube and floor serve as reference (non-emissive).
|
||||
|
||||
Bloom is a 4-pass GPU pipeline: threshold → blur H → blur V → composite.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example bloom
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `+` / `-` | **Bloom threshold** +0.1 / −0.1 |
|
||||
| `[` / `]` | **Bloom intensity** +0.1 / −0.1 |
|
||||
| `I` / `O` | **Bloom radius** +0.5 / −0.5 |
|
||||
| `E` / `Q` | Exposure ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposure |
|
||||
|
||||
### What to observe
|
||||
|
||||
- **Low threshold** (0.0): the entire image "blooms" (very diffuse effect).
|
||||
- **High threshold** (2.0+): only the bright emissive spheres produce glow.
|
||||
- **Intensity 0.0**: no visible glow (even though the threshold extracts pixels).
|
||||
- **Large radius** (10+): the glow spreads over a large area.
|
||||
|
||||
---
|
||||
|
||||
## `hdr` — HDR + Tone Mapping
|
||||
|
||||
Demonstrates HDR rendering with the ACES Filmic curve. Three objects:
|
||||
|
||||
- **Cube**: normal lighting (no emissive) — LDR reference.
|
||||
- **Bright sphere** (emissive 3.0): without HDR, it would be clamped to white.
|
||||
With ACES, highlights "roll off" smoothly toward white.
|
||||
- **Dark sphere** (emissive 0.3): stays dark even at high exposure.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example hdr
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `E` | **Exposure ×1.3** (brighter) |
|
||||
| `Q` | **Exposure ÷1.3** (darker) |
|
||||
| `0` | Reset exposure to 1.0 |
|
||||
|
||||
### What to observe
|
||||
|
||||
- At exposure 1.0: the bright sphere is white but with detail (ACES rolloff).
|
||||
- At high exposure (E×E×E): the scene brightens, the bright sphere stays white
|
||||
(saturated), but the cube gains detail.
|
||||
- At low exposure (Q×Q): everything darkens, the bright sphere becomes orange
|
||||
(HDR values > 1.0 are compressed).
|
||||
|
||||
> **Note**: the tone mapper is compiled into the pipeline at build time. To
|
||||
> compare ACES vs Reinhard, change `ToneMapper::Aces` → `ToneMapper::Reinhard`
|
||||
> in the source.
|
||||
|
||||
---
|
||||
|
||||
## `msaa` — MSAA 4× (Anti-aliasing)
|
||||
|
||||
Demonstrates multisample anti-aliasing: object edges (cube, sphere) are smooth
|
||||
instead of "stair-stepped". The scene contains a cube (sharp edges), a sphere
|
||||
(curved silhouette), and a small cube near the camera (maximum aliasing).
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example msaa
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `M` | Show sample count |
|
||||
|
||||
### To compare with/without MSAA
|
||||
|
||||
Remove the `.with_msaa(4)` line in the source and recompile: the scene is
|
||||
identical, only the edges differ (stair-stepped vs smooth).
|
||||
|
||||
> **Note**: MSAA is a build-time setting (multisample texture allocation). It
|
||||
> works independently of HDR: with HDR, the MSAA texture is `Rgba16Float` and
|
||||
> resolves into the HDR texture before bloom/TM.
|
||||
|
||||
---
|
||||
|
||||
## `fog` — Distance Fog
|
||||
|
||||
Demonstrates the 3 fog modes: **linear**, **exponential**, **exponential²**.
|
||||
The scene contains a row of cubes receding into the distance and scattered
|
||||
spheres on a large floor plane. Fog blends objects toward a background color,
|
||||
creating the illusion of an infinite world.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example fog --features "all-prims"
|
||||
```
|
||||
|
||||
**Keys**: `1` = linear, `2` = exp, `3` = exp², `4` = off, `R` = reset.
|
||||
|
||||
> Fog is applied in the main fragment shader (after lighting, before tone
|
||||
> mapping). It uses the Euclidean distance from the fragment to the camera.
|
||||
|
||||
---
|
||||
|
||||
## `dof` — Depth of Field (Cinematic Bokeh)
|
||||
|
||||
Demonstrates depth of field blur: an object at the focus plane stays sharp
|
||||
while foreground and background blur according to their distance from the
|
||||
focus plane. Creates a natural attention effect (cinematic style).
|
||||
|
||||
The scene contains 20 cubes in a row along Z (z=3 to z=-25.5) and 5 spheres to
|
||||
the sides, on a floor plane. Focus presets at 3 m / 8 m / 15 m.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example dof --features "all-prims"
|
||||
```
|
||||
|
||||
**Keys**: `1` = cinematic, `2` = subtle, `3` = focus 3 m, `4` = focus 15 m,
|
||||
`5` = off, `R` = reset.
|
||||
|
||||
> DoF operates in linear HDR (after bloom, before tone mapping). Two passes:
|
||||
> CoC (depth → per-pixel blur radius) then 12-tap disc blur with variable radius.
|
||||
@@ -0,0 +1,124 @@
|
||||
# Lights, Shadows & Emissive
|
||||
|
||||
Examples covering **lighting**: shadow mapping, isolated light types, and
|
||||
emissive materials.
|
||||
|
||||
| Example | Run command | What it shows |
|
||||
|---------|-------------|---------------|
|
||||
| `shadow` | `cargo run -p wsg-lib --example shadow` | Shadow mapping in isolation (directional light, 4 objects on a floor) |
|
||||
| `shadow_test` | `cargo run -p wsg-lib --example shadow_test` | Dedicated shadow test: one directional caster, cube on a ground slab, PCF-softened |
|
||||
| `spot_test` | `cargo run -p wsg-lib --example spot_test` | Isolated spot light: directed beam, penumbra, attenuation |
|
||||
| `emissive` | `cargo run -p wsg-lib --example emissive` | Emissive materials (increasing intensities 0 → 4.0) |
|
||||
|
||||
> All commands run from the repo root.
|
||||
|
||||
---
|
||||
|
||||
## `shadow` — Shadow Mapping
|
||||
|
||||
Four objects (cube, sphere, cone, cylinder) on a floor, lit by a directional
|
||||
light that casts shadows. Shadow quality is controlled by `ShadowConfig`
|
||||
(map size, anti-acne bias).
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example shadow
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `1` | Front view |
|
||||
| `2` | Side view |
|
||||
| `3` | **Top view** (see shadow shapes clearly) |
|
||||
| `L` | Change light direction (3 presets) |
|
||||
|
||||
### What to observe
|
||||
|
||||
- The cube rotates slowly → its shadow moves on the floor.
|
||||
- The sphere has a smooth shadow/light transition (soft terminator).
|
||||
- The cone produces a distinct triangular shadow.
|
||||
- In top view (`3`), you see the exact shape of projected shadows.
|
||||
- Shadow map size (1024 default) determines resolution: modify
|
||||
`SHADOW_MAP_SIZE` at the top of the file to test 256 (pixelated) or 2048 (sharp).
|
||||
|
||||
---
|
||||
|
||||
## `shadow_test` — Dedicated Shadow Mapping Test
|
||||
|
||||
A single **directional** light is configured as the shadow caster
|
||||
(`Scene::set_shadow_caster(Some(0))`). The cube sits on a large thin ground
|
||||
slab, so its silhouette is projected as a crisp PCF-softened shadow. With a
|
||||
small ambient term the shadow is clearly visible and the light/shadow
|
||||
directions are easy to read:
|
||||
|
||||
1. the **blocker** (cube) casts a directional shadow that stretches along the
|
||||
ground opposite the light direction — the light sits at the camera's
|
||||
front-right and low-ish, so the shadow runs clearly across the ground to
|
||||
the left of the cube,
|
||||
2. the shadow edge is **softened** by 3×3 PCF (no hard jagged border),
|
||||
3. the lit faces are bright while the shadowed ground stays near-ambient,
|
||||
proving the depth comparison is applied per-pixel.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example shadow_test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `spot_test` — Isolated Spot Light
|
||||
|
||||
**Only** a spot light is on (the default directional light is removed via
|
||||
`clear_lights()`) and the ambient is deliberately **very low**. The rotating
|
||||
cube therefore appears nearly black except where the spot's cone reaches it —
|
||||
you clearly see:
|
||||
|
||||
1. a **directed beam** (not an omni halo like the point light),
|
||||
2. a **smoothed edge** (penumbra) at the cone's limit,
|
||||
3. the lighting that **follows the cube** as it rotates (the cone is fixed in
|
||||
world space).
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example spot_test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## `emissive` — Emissive Materials
|
||||
|
||||
Five spheres in a row with increasing emissive intensities:
|
||||
|
||||
| Sphere | Color | Intensity | Effect |
|
||||
|--------|-------|-----------|--------|
|
||||
| 1 | Gray | 0.0 | No glow (reference) |
|
||||
| 2 | Orange | 0.5 | Slight glow |
|
||||
| 3 | Yellow | 1.0 | Visible glow |
|
||||
| 4 | Green | 2.0 | HDR glow (beyond 1.0) |
|
||||
| 5 | Blue | 4.0 | Intense glow (saturation) |
|
||||
|
||||
With HDR, intensities > 1.0 produce a true "glow" (values exceed [0,1] in
|
||||
linear space). Without HDR, they would be clamped to white.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example emissive
|
||||
```
|
||||
|
||||
### Keys
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| Drag (LMB) | Orbit camera |
|
||||
| Wheel | Zoom |
|
||||
| `R` | Reset camera |
|
||||
| `E` / `Q` | Exposure ×1.3 / ÷1.3 |
|
||||
| `0` | Reset exposure |
|
||||
| `C` | **Cycle emissive multiplier** (1× → 2× → 0.5× → …) |
|
||||
|
||||
### What to observe
|
||||
|
||||
- Sphere 1 (intensity 0) is simply lit by the directional light.
|
||||
- Spheres 2-5 glow with their own light, independent of scene lighting.
|
||||
- `C` doubles or halves all intensities simultaneously (to see the HDR effect).
|
||||
@@ -0,0 +1,118 @@
|
||||
# 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 (checkerboard) cube, lit (directional + point + spot), spinning |
|
||||
| `pbr` | `cargo run -p wsg-lib --example pbr` | PBR metallic/roughness + normal mapping |
|
||||
| `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 a procedural 8×8 checkerboard
|
||||
via the diffuse path (bind group `@group(2)`). Follows the declarative workflow
|
||||
(like `simple`): `AppBuilder` + automatic scene, **no wgpu import**. The texture
|
||||
is generated procedurally (RGBA bytes → `Texture::from_rgba8`) to stay
|
||||
self-contained; 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,
|
||||
bump map, matte floor). The bump-map cube shows procedural sin-wave surface
|
||||
detail.
|
||||
|
||||
---
|
||||
|
||||
## `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.
|
||||
Reference in New Issue
Block a user