HDR
This commit is contained in:
@@ -20,6 +20,7 @@ GPU graphics background is required.
|
||||
| [Materials & textures](materials.md) | Appearance: the `standard` shader, unlit mode, diffuse textures |
|
||||
| [Lights](lights.md) | Directional, point, spot, ambient, `MAX_LIGHTS` |
|
||||
| [Shadows](shadows.md) | Shadow mapping: picking the casting light, the packed-index pitfall |
|
||||
| [HDR & tone mapping](hdr.md) | Offscreen float render + ACES/Reinhard, opt-in via `with_hdr` |
|
||||
| [GPU-driven rendering](gpu-driven.md) | GPU world matrices + indirect draws, opt-in frustum culling |
|
||||
| [Camera & input](camera-input.md) | Active camera, orbital controller, unified keyboard/mouse state |
|
||||
| [Examples](examples.md) | The 7 repo examples, the advanced `manual` workflow, adding your own example |
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# HDR & Tone Mapping
|
||||
|
||||
> **Étape 20** — Opt-in HDR rendering with tone mapping.
|
||||
|
||||
## What it does
|
||||
|
||||
By default, the WSG renderer draws directly to the window's sRGB surface. Color values
|
||||
above 1.0 are **clipped** (saturated to white) — you lose all information in bright areas.
|
||||
|
||||
When HDR is enabled, the pipeline becomes:
|
||||
|
||||
```
|
||||
Main pass → offscreen Rgba16Float texture (unbounded float)
|
||||
TM pass → fullscreen triangle samples HDR texture, applies curve, writes to sRGB surface
|
||||
```
|
||||
|
||||
The tone mapping **compresses** the [0, ∞) range to [0, 1] with a perceptual curve,
|
||||
so bright areas are smoothly rolled off instead of clipping.
|
||||
|
||||
## Enabling HDR
|
||||
|
||||
```rust
|
||||
use wsg_lib::core::ToneMapper;
|
||||
use wsg_lib::app::AppBuilder;
|
||||
|
||||
let app = AppBuilder::new()
|
||||
.title("My HDR App")
|
||||
.with_hdr(ToneMapper::Aces) // ← enables HDR
|
||||
.build()
|
||||
.await?;
|
||||
```
|
||||
|
||||
Without `.with_hdr(...)`, the renderer operates in LDR mode (direct to surface, zero overhead).
|
||||
|
||||
## Tone mapping curves
|
||||
|
||||
| Variant | Curve | Use case |
|
||||
|---------|-------|----------|
|
||||
| `ToneMapper::Aces` | ACES Filmic (Narkowicz 2015) | Cinematic look, soft highlight rolloff, good contrast |
|
||||
| `ToneMapper::Reinhard` | `x / (1 + x)` | Simple, flat; less contrast but computationally trivial |
|
||||
|
||||
The curve is **compiled into the pipeline** at construction time (one WGSL entry point
|
||||
per variant) — there is no runtime branching cost.
|
||||
|
||||
## Cost
|
||||
|
||||
| HDR state | Extra per-frame cost |
|
||||
|-----------|---------------------|
|
||||
| Disabled (default) | **Zero** — no texture, no pass, no pipeline |
|
||||
| Enabled | +1 fullscreen render pass (triangle, 3 verts) + 1 offscreen texture (same size as window) |
|
||||
|
||||
The extra pass is negligible on any GPU (a few hundred microseconds). The offscreen
|
||||
texture costs ~12 bytes/pixel of VRAM (RGBA16F = 8 bytes/px + the surface's own buffer).
|
||||
|
||||
## How it works (technical)
|
||||
|
||||
- **Offscreen texture**: `Rgba16Float`, same size as the window. Created in `Renderer::new`,
|
||||
recreated on resize.
|
||||
- **Main pass**: the color attachment targets the HDR texture instead of the surface.
|
||||
The `standard_shader.wgsl` fragment output (linear float, unbounded) is stored as-is.
|
||||
- **TM pass**: a fullscreen triangle (3 vertices, no vertex buffer) samples the HDR texture,
|
||||
multiplies by exposure (currently fixed at 1.0), applies the tone curve, and writes to
|
||||
the sRGB surface. The hardware performs the linear→sRGB gamma conversion automatically
|
||||
(the surface format is `Rgba8UnormSrgb`).
|
||||
- **No double gamma**: the shader outputs linear [0,1]; the sRGB surface encoding is
|
||||
handled by the rasterizer.
|
||||
|
||||
## Exposure
|
||||
|
||||
Currently fixed at 1.0 (no user control yet). A future step will expose an
|
||||
`exposure` field in a `HdrConfig` struct for live adjustment.
|
||||
|
||||
## See also
|
||||
|
||||
- [Shadows](shadows.md) — the other opt-in visual feature
|
||||
- [GPU-driven rendering](gpu-driven.md) — the compute pipeline that feeds the main pass
|
||||
- [Examples](examples.md) — the `demo` example enables HDR by default
|
||||
Reference in New Issue
Block a user