eng doc
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
# Bloom (Step 23)
|
||||
|
||||
**Bloom** is a post-process that creates a "glow" effect around the bright areas of the image.
|
||||
Pixels whose luminance exceeds a threshold are extracted, blurred, then added back to the
|
||||
original image.
|
||||
|
||||
> **Prerequisite**: bloom requires HDR (`AppBuilder::with_hdr`). Without HDR, values are already
|
||||
> clamped to [0,1] and there is nothing "bright" to extract.
|
||||
|
||||
## Activation
|
||||
|
||||
```rust
|
||||
use wsg_lib::prelude::*;
|
||||
|
||||
let app = AppBuilder::new()
|
||||
.with_hdr(ToneMapper::Aces) // required
|
||||
.with_bloom(BloomConfig {
|
||||
threshold: 1.0, // HDR luminance threshold
|
||||
knee: 0.5, // soft-knee width
|
||||
intensity: 0.8, // glow intensity
|
||||
radius: 4.0, // blur radius (pixels, half-res)
|
||||
..Default::default()
|
||||
})
|
||||
.build()
|
||||
.await?;
|
||||
```
|
||||
|
||||
## `BloomConfig`
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `threshold` | `f32` | `1.0` | Luminance threshold (linear HDR units). Only pixels above the threshold contribute to the bloom. |
|
||||
| `knee` | `f32` | `0.5` | Soft-knee width. Larger = smoother transition. |
|
||||
| `intensity` | `f32` | `0.8` | Multiplier applied to the blurred result before adding it to the HDR. |
|
||||
| `radius` | `f32` | `4.0` | Blur radius in pixels (at half resolution). Larger = wider glow. |
|
||||
|
||||
## Runtime update
|
||||
|
||||
```rust
|
||||
// In the handler (fn update):
|
||||
if app.bloom_enabled() {
|
||||
app.set_bloom_config(BloomConfig {
|
||||
intensity: new_intensity,
|
||||
..app.bloom_config()
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Changes take effect on the next frame (the uniforms are re-written every frame).
|
||||
|
||||
## Pipeline (4 GPU passes)
|
||||
|
||||
```
|
||||
Scene ──→ HDR (full res, Rgba16Float)
|
||||
│
|
||||
├──→ [1] Threshold (full → half res)
|
||||
│ Soft-knee: smoothstep(knee, knee+1, lum)
|
||||
│
|
||||
├──→ [2] Blur H (half res)
|
||||
│ 9-tap separable Gaussian, direction = (1/w, 0)
|
||||
│
|
||||
├──→ [3] Blur V (half res)
|
||||
│ 9-tap separable Gaussian, direction = (0, 1/h)
|
||||
│ (ping-pong: writes into the bright texture)
|
||||
│
|
||||
└──→ [4] Composite (full res)
|
||||
output = HDR + bloom × intensity
|
||||
(writes into a 3rd full-res texture)
|
||||
│
|
||||
▼
|
||||
Tone Mapping (reads the composite)
|
||||
│
|
||||
▼
|
||||
Surface (sRGB)
|
||||
```
|
||||
|
||||
## Cost
|
||||
|
||||
- **Without bloom** (default): zero overhead. The TM reads the HDR texture directly.
|
||||
- **With bloom**: 4 extra passes (1 full-res + 3 half-res) + 3 intermediate textures. The cost
|
||||
is moderate because the blur runs at half resolution.
|
||||
|
||||
## Non-regression
|
||||
|
||||
- `with_bloom()` without `with_hdr()` → warning + no-op (the bloom is ignored).
|
||||
- Without `with_bloom()` → the TM reads the HDR texture directly (the Step 20 behavior is
|
||||
unchanged).
|
||||
|
||||
## Limitations (MVP)
|
||||
|
||||
- A single mip level (no multi-mip "soft" bloom à la Unreal).
|
||||
- No directional bloom.
|
||||
- The blur is a 9-tap Gaussian (good enough for a "soft" glow).
|
||||
- No per-layer bloom (no per-material "bloom mask").
|
||||
|
||||
## Links
|
||||
|
||||
- [User README](../README.md) · [HDR & tone mapping](hdr.md) · [Examples](../examples.md)
|
||||
- [Root README](../../../README.md)
|
||||
Reference in New Issue
Block a user