108 lines
3.5 KiB
Markdown
108 lines
3.5 KiB
Markdown
# É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é.
|