# 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)