Files
wsg/docs/user/lights/emissive-exposure.md
T
Jérôme Bousquié d4c2d93fc5 eng doc
2026-09-25 20:06:10 +02:00

115 lines
3.5 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.
# Emissive + Exposure
## Principle
Two complementary features (Step 22):
| Feature | Effect | Cost |
|---------|--------|------|
| **Exposure** (6.1) | Multiplies luminance before the tone-mapping curve | Zero when HDR is inactive |
| **Emissive** (6.2) | Adds an emitted color (independent of the lights) | Zero when `emissive = [0,0,0,0]` |
## Exposure
### API
```rust
// Initialization (optional, default = 1.0)
let app = AppBuilder::new()
.with_hdr(ToneMapper::Aces)
.with_exposure(1.5) // start brighter
.build().await?;
// Runtime (in update())
app.set_exposure(app.exposure() * 1.1); // +1 "stop"
app.set_exposure(1.0); // reset
```
### Behavior
- Exposure is a **multiplier** applied to the HDR texture before the tone-mapping curve.
- `exposure = 2.0` → the image is 2× brighter (like opening a camera's aperture).
- `exposure = 0.5` → the image is 2× darker.
- Clamped to `[0.01, 10.0]` to avoid degenerate values.
- **Only has an effect when HDR is active** (`with_hdr(...)`). In LDR the value is ignored.
### Keyboard (demo)
| Key | Effect |
|-----|--------|
| `+` | ×1.1 (brighter) |
| `-` | ÷1.1 (darker) |
| `0` | Reset to 1.0 |
## Emissive
### API
```rust
use wsg_lib::resources::Material;
// Create a material with emissivity
let mut mat = /* ... */;
mat.emissive = [1.0, 0.3, 0.1, 1.5]; // orange, intensity 1.5 (> 1.0 = HDR glow)
```
### Format
`emissive = [r, g, b, intensity]`:
- **rgb**: the emission color (same space as the vertex base color)
- **a (intensity)**: the multiplier. `1.0` = normal color, `> 1.0` = highlight (only visible in HDR)
### Shader formula
```
final_color = lit + base_color * emissive.rgb * emissive.a
```
- The emission is **additive**: visible even in total darkness (no light needed).
- It is **independent of shadows**: an emissive object casts no shadow and is not shadowed.
- `emissive = [0,0,0,0]` (default) → no change (non-regression guaranteed).
### Use cases
| Use | Value |
|-----|-------|
| LED / indicator | `[0, 1, 0, 1.0]` (green, normal intensity) |
| Flame / sun | `[1, 0.8, 0.2, 3.0]` (orange, HDR glow) |
| Neon | `[0, 0.5, 1, 2.5]` (cyan, glow) |
| Inactive | `[0, 0, 0, 0]` (default) |
### Keyboard (demo)
| Key | Effect |
|-----|--------|
| `E` | Toggle orange glow on the sphere/cylinder |
## Interactions
| Combination | Result |
|-------------|--------|
| Emissive + HDR + ACES | Soft glow, highlights roll off (the nicest) |
| Emissive + LDR | Clamped to 1.0 (no glow, but the color is visible in the dark) |
| Emissive + shadows | The emissive object is NOT shadowed (emission bypasses the shadow term) |
| Exposure + Emissive | Exposure also amplifies the emission (consistent: everything is in the HDR texture) |
## Non-regression
- **Emissive**: `[0,0,0,0]` by default → the shader adds `base * 0 * 0 = 0` → no change.
- **Exposure**: `1.0` by default → `pow(color, 1/1) = color` → no change.
- Both are **opt-in**: without `with_hdr(...)` and `emissive != 0`, the pipeline is identical
to the previous state.
## Limitations (MVP)
- Emissive is **per material**, not per vertex (no emission gradient within a mesh).
- Emissive is **static** at material creation (changing `mat.emissive` requires re-registering
the material via `add_material`).
- No **bloom** (Step 23): the HDR glow is visible but not "blurred" / spread.
## Links
- [User README](../README.md) · [HDR & tone mapping](../effects/hdr.md) · [Examples](../examples.md)
- [Root README](../../../README.md)