# Émissive + Exposure ## Principe Deux features complémentaires (Étape 22) : | Feature | Effet | Coût | |---------|-------|------| | **Exposure** (6.1) | Multiplie la luminance avant la courbe de tone mapping | Zéro si HDR inactif | | **Emissive** (6.2) | Ajoute une couleur émise (indépendante des lumières) | Zéro si `emissive = [0,0,0,0]` | ## Exposure ### API ```rust // Initialisation (optionnel, default = 1.0) let app = AppBuilder::new() .with_hdr(ToneMapper::Aces) .with_exposure(1.5) // démarre plus clair .build().await?; // Runtime (dans update()) app.set_exposure(app.exposure() * 1.1); // +1 "stop" app.set_exposure(1.0); // reset ``` ### Comportement - L'exposure est un **multiplicateur** appliqué à la texture HDR avant la courbe de tone mapping. - `exposure = 2.0` → l'image est 2× plus claire (comme ouvrir le diaphragme d'un photo). - `exposure = 0.5` → l'image est 2× plus sombre. - Clampé à `[0.01, 10.0]` pour éviter les valeurs dégénérées. - **N'a d'effet que si HDR est actif** (`with_hdr(...)`). En LDR, la valeur est ignorée. ### Clavier (demo) | Touche | Effet | |--------|-------| | `+` | ×1.1 (plus clair) | | `-` | ÷1.1 (plus sombre) | | `0` | Reset à 1.0 | ## Emissive ### API ```rust use wsg_lib::resources::Material; // Créer un matériau avec émissivité let mut mat = /* ... */; mat.emissive = [1.0, 0.3, 0.1, 1.5]; // orange, intensité 1.5 (> 1.0 = glow HDR) ``` ### Format `emissive = [r, g, b, intensity]` : - **rgb** : la couleur de l'émission (même espace que la couleur base du vertex) - **a (intensity)** : le multiplicateur. `1.0` = couleur normale, `> 1.0` = surbrillance (ne se voit qu'en HDR) ### Formule shader ``` final_color = lit + base_color * emissive.rgb * emissive.a ``` - L'émission est **additive** : visible même dans le noir total (pas de lumière nécessaire). - Elle est **indépendante des ombres** : un objet émissif ne projette pas d'ombre et n'est pas ombragé. - `emissive = [0,0,0,0]` (default) → aucun changement (non-régression garantie). ### Cas d'usage | Usage | Valeur | |-------|--------| | LED / indicateur | `[0, 1, 0, 1.0]` (vert, intensité normale) | | Flamme / soleil | `[1, 0.8, 0.2, 3.0]` (orange, glow HDR) | | Neon | `[0, 0.5, 1, 2.5]` (cyan, glow) | | Inactif | `[0, 0, 0, 0]` (default) | ### Clavier (demo) | Touche | Effet | |--------|-------| | `E` | Toggle glow orange sur la sphère/cylindre | ## Interactions | Combination | Résultat | |-------------|----------| | Emissive + HDR + ACES | Glow doux, highlights roll off (le plus joli) | | Emissive + LDR | Clamped à 1.0 (pas de glow, mais couleur visible dans le noir) | | Emissive + shadows | L'objet émissif n'est PAS ombragé (l'émission bypass le shadow term) | | Exposure + Emissive | L'exposure amplifie aussi l'émission (cohérent : tout est dans la texture HDR) | ## Non-régression - **Emissive** : `[0,0,0,0]` par défaut → le shader additionne `base * 0 * 0 = 0` → aucun changement. - **Exposure** : `1.0` par défaut → `pow(color, 1/1) = color` → aucun changement. - Les deux sont **opt-in** : sans `with_hdr(...)` ni `emissive != 0`, le pipeline est identique à l'état précédent. ## Limitations (MVP) - L'emissive est **par matériau**, pas par vertex (pas de gradient d'émission dans un mesh). - L'emissive est **statique** à la création du matériau (changer `mat.emissive` requiert de re-registrer le matériau via `add_material`). - Pas de **bloom** (Étape 23) : le glow HDR est visible mais pas "flou" / diffusé.