Files
wsg/docs/user/msaa.md
T
Jérôme Bousquié 24fbafc810 réorg doc
2026-09-25 19:08:20 +02:00

128 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MSAA (Anti-aliasing)
Multi-Sample Anti-Aliasing (MSAA) smooths jagged edges by rendering the scene
at a higher sample count (e.g. 4 samples per pixel), then averaging the samples
into the final image.
## Activation
MSAA is opt-in via the builder. When disabled (default), the renderer uses
single-sample rendering with zero overhead:
```rust
let app = AppBuilder::new()
.title("My App")
.with_msaa(4) // 4× MSAA (also: 2 or 8)
.build()
.await?;
```
## How it works
MSAA is a **rasterizer feature** — no new shader is needed. The pipeline:
```text
┌─────────────────────────────────────────────────────────────────────┐
│ Without MSAA (default) │
│ │
│ Main pass ──→ HDR texture (1 sample) ──→ [Bloom] ──→ TM ──→ Surface │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ With MSAA 4× (and HDR) │
│ │
│ Main pass ──→ MSAA texture (4 samples, Rgba16Float) │
│ ↓ resolve (hardware average) │
│ HDR texture (1 sample) │
│ ↓ │
│ [Bloom] ──→ TM ──→ Surface │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ With MSAA 4× (no HDR) │
│ │
│ Main pass ──→ MSAA texture (4 samples, surface format) │
│ ↓ resolve │
│ Swapchain (surface) │
└─────────────────────────────────────────────────────────────────────┘
```
Key points:
- The **main scene pass** renders into the MSAA texture (N samples/pixel).
- The **resolve** (hardware average) produces the single-sample output.
- **Post-processes** (bloom, tone mapping) operate on the **resolved**
single-sample texture — they are completely unaffected by MSAA.
- The **shadow map** is always single-sample (depth-only, not visible directly).
## Sample count
| Count | Quality | Cost (approx.) | Use case |
|-------|---------|----------------|----------|
| 2 | Basic | ~1.1× | Low-end / battery |
| **4** | **Good** | **~1.3–1.5×** | **Default, most games** |
| 8 | Excellent | ~1.6–2.0× | High-end / static scenes |
The cost is in the rasterizer/fill-rate (each pixel is shaded N times at
triangles' edges). Interior pixels (covered by a single triangle) are
shaded only once — MSAA only multiplies the **edge** cost.
## Runtime query
```rust
// In AppHandler::setup or update:
let active = app.renderer().msaa_enabled(); // true if sample_count > 1
let count = app.renderer().msaa_sample_count(); // 1, 2, 4, or 8
```
MSAA is a **build-time** setting: the multi-sample textures are allocated
at startup. Changing the sample count requires recreating the textures
(window resize does this automatically).
## Configuration struct
```rust
use wsg_lib::MsaaConfig;
let config = MsaaConfig { sample_count: 4 };
// Or use the builder shortcut (validated):
let app = AppBuilder::new().with_msaa(4).build().await?;
```
## Compatibility
| Feature | Compatible? | Notes |
|---------|-------------|-------|
| HDR + Tone Mapping | ✅ | MSAA texture is `Rgba16Float`, resolves into HDR |
| Bloom | ✅ | Bloom reads the resolved (single-sample) HDR texture |
| Shadows | ✅ | Shadow map is always single-sample |
| Frustum Culling | ✅ | Independent (compute pass) |
| LOD | ✅ | Independent (draw args) |
| Emissive | ✅ | Per-entity, in the main pass |
## Limitations
- **Does not smooth UV-dependent aliasing** (texture shimmer). For that,
use mipmaps + anisotropic filtering (future: texture module).
- **Cost scales with overdraw**: fully transparent or heavily overlapping
geometry pays the full N× cost.
- **GPU support**: most modern GPUs support 4× for all formats. 8× may be
limited for float formats (check `Device::limits().max_color_attachment_samples`).
## Example
```rust
use wsg_lib::app::AppBuilder;
use wsg_lib::core::ToneMapper;
let app = AppBuilder::new()
.title("MSAA Demo")
.size(1280, 720)
.with_msaa(4)
.with_hdr(ToneMapper::Aces)
.build()
.await?;
```
See `lib/examples/effects/msaa.rs` for a full interactive demo with cube, sphere,
and ground plane where aliasing is clearly visible without MSAA.