eng doc
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# Distance fog
|
||||
|
||||
## Principle
|
||||
|
||||
Distance fog blends objects toward a predefined color based on their distance to the camera.
|
||||
It is the standard tool for:
|
||||
|
||||
- **Hiding the rendered edge of the world** — the illusion of an infinite world (Skyrim, GTA,
|
||||
Minecraft)
|
||||
- **Adding depth** — a natural atmospheric effect
|
||||
- **Masking transitions** — tile loading, LOD pops
|
||||
|
||||
## Activation
|
||||
|
||||
```rust
|
||||
use wsg_lib::prelude::*;
|
||||
|
||||
let app = AppBuilder::new()
|
||||
.with_fog(FogConfig::exponential2([0.7, 0.75, 0.85], 0.06))
|
||||
.build()
|
||||
.await?;
|
||||
```
|
||||
|
||||
Without `.with_fog()`, fog is disabled — **zero GPU cost** (the shader branch is never taken).
|
||||
|
||||
## Modes
|
||||
|
||||
| Mode | Formula | Use |
|
||||
|------|---------|-----|
|
||||
| `Linear` | `saturate((far - d) / (far - near))` | Sharp cutoff between two distances |
|
||||
| `Exponential` | `exp(-density × d)` | Natural fog (forest, lake) |
|
||||
| `Exponential2` | `exp(-density² × d²)` | Gradual start, sharp cutoff — **ideal for masking** |
|
||||
|
||||
### Constructors
|
||||
|
||||
```rust
|
||||
// Linear: fade between near and far
|
||||
FogConfig::linear([0.7, 0.8, 0.9], 5.0, 50.0)
|
||||
|
||||
// Exponential: natural fade
|
||||
FogConfig::exponential([0.6, 0.7, 0.8], 0.03)
|
||||
|
||||
// Exponential²: world-edge masking
|
||||
FogConfig::exponential2([0.7, 0.75, 0.85], 0.08)
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `mode` | `FogMode` | Linear / Exponential / Exponential2 |
|
||||
| `color` | `[f32; 3]` | Fog color (RGB, linear space) |
|
||||
| `near` | `f32` | Start distance (linear mode only) |
|
||||
| `far` | `f32` | End distance, full fog (linear mode) |
|
||||
| `density` | `f32` | Density (exp / exp² modes). Typical: 0.01–0.3 |
|
||||
|
||||
### Choosing the color
|
||||
|
||||
The fog color **must match the sky/clear color** for a seamless "infinite world" effect. With
|
||||
HDR + ACES, use linear values consistent with the tone mapping.
|
||||
|
||||
### Choosing the density (exp²)
|
||||
|
||||
To mask the edge of the world at a distance `D`:
|
||||
|
||||
```
|
||||
density ≈ 2.0 / D
|
||||
```
|
||||
|
||||
Examples:
|
||||
- World visible up to 25 units → `density = 0.08`
|
||||
- World visible up to 50 units → `density = 0.04`
|
||||
- World visible up to 100 units → `density = 0.02`
|
||||
|
||||
## Runtime change
|
||||
|
||||
```rust
|
||||
// In update():
|
||||
if key_pressed(KeyCode::Digit1) {
|
||||
app.renderer_mut().set_fog(Some(FogConfig::linear([0.7, 0.8, 0.9], 5.0, 30.0)));
|
||||
}
|
||||
if key_pressed(KeyCode::Digit4) {
|
||||
app.renderer_mut().set_fog(None); // disable
|
||||
}
|
||||
```
|
||||
|
||||
The change takes effect on the next frame.
|
||||
|
||||
## Pipeline
|
||||
|
||||
```text
|
||||
Main pass (fragment shader)
|
||||
↓
|
||||
Lighting → final_rgb
|
||||
↓
|
||||
FOG: mix(final_rgb, fog_color, 1 - fog_factor) ← here
|
||||
↓
|
||||
→ HDR texture / swapchain
|
||||
↓
|
||||
(Bloom) → Tone Mapping → surface
|
||||
```
|
||||
|
||||
Fog is applied **before** tone mapping: HDR values stay unclamped, and the TM applies the
|
||||
ACES/Reinhard curve to the already-fogged result. Result: the fog is perceptually coherent.
|
||||
|
||||
## Compatibility
|
||||
|
||||
| With | OK? | Note |
|
||||
|------|-----|------|
|
||||
| HDR + TM | ✅ | Fog before TM (recommended) |
|
||||
| Bloom | ✅ | Bloom extracts the bright areas of the post-fog result |
|
||||
| MSAA | ✅ | Independent (rasterizer vs fragment shader) |
|
||||
| GPU culling | ✅ | Independent (culling decides what to draw, fog decides the color) |
|
||||
| Shadows | ✅ | The shadow is computed before the fog |
|
||||
|
||||
## Limitations (v1)
|
||||
|
||||
- **Scene-level only**: a single fog for the whole scene. Per-material fog would require an
|
||||
extra parameter in the per-object bind group.
|
||||
- **Euclidean distance**: no volumetric or directional fog.
|
||||
- **Fixed color**: no color gradient with distance.
|
||||
|
||||
## Example
|
||||
|
||||
See `lib/examples/effects/fog.rs`: 15 cubes in a row + 5 spheres on an 80×80 plane, with
|
||||
runtime switching between the 3 modes.
|
||||
|
||||
```sh
|
||||
cargo run -p wsg-lib --example fog --features "all-prims"
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
- [User README](../README.md) · [HDR & tone mapping](hdr.md) · [Examples](../examples.md)
|
||||
- [Root README](../../../README.md)
|
||||
Reference in New Issue
Block a user