85 lines
3.3 KiB
Markdown
85 lines
3.3 KiB
Markdown
# Lights
|
|
|
|
Lights are **scene-global**: a single list is packed into the frame uniforms every frame, and
|
|
**all** entities receive their lighting (per-material lights are out of the current scope).
|
|
|
|
## Model
|
|
|
|
- Bounded capacity: **`MAX_LIGHTS = 8`** lights in total (directional + point + spot
|
|
combined). Adding beyond that returns an error.
|
|
- **Default**: one white directional light along **+Z** (from the surface point toward the
|
|
light) + white ambient. This default exactly reproduces the historical single-light
|
|
rendering — your scene "just works" with no configuration.
|
|
- Ambient (`set_ambient`) is a global hemispherical term, independent of the lights.
|
|
|
|
## Adding lights
|
|
|
|
```rust
|
|
use glam::Vec3;
|
|
|
|
// Directional: `dir` points FROM the surface point TOWARD the light.
|
|
app.scene
|
|
.add_directional_light(Vec3::new(1.0, 1.2, 1.0).normalize(), [1.0, 0.98, 0.92], 1.5)
|
|
.unwrap();
|
|
|
|
// Point: world position, tint, intensity, attenuation radius (linear down to 0).
|
|
app.scene
|
|
.add_point_light(Vec3::new(0.5, 1.6, 1.8), [1.0, 0.7, 0.3], 1.2, 6.0)
|
|
.unwrap();
|
|
|
|
// Spot: position, cone axis (FROM the light TOWARD the scene), tint, intensity, radius,
|
|
// half-angle in radians (penumbra smoothed at the edge).
|
|
app.scene.add_spot_light(
|
|
Vec3::new(-2.5, 2.2, 1.0), // position
|
|
Vec3::new(2.5, -2.2, -1.0).normalize(), // axis, toward the scene
|
|
[0.3, 1.0, 0.5], // green tint
|
|
1.4, 8.0, 0.45, // intensity, radius, half-angle (~26°)
|
|
).unwrap();
|
|
```
|
|
|
|
These three calls are the ones in the [`demo`](../../lib/examples/demo.rs) example;
|
|
[`cube.rs`](../../lib/examples/cube.rs) shows a point + a spot on top of the default
|
|
directional, and [`spot_test.rs`](../../lib/examples/spot_test.rs) isolates a single spot
|
|
(ambient nearly zero).
|
|
|
|
Global settings:
|
|
|
|
| Method | Effect |
|
|
|---------|--------|
|
|
| `set_ambient([r, g, b])` | hemispherical ambient color (default white) |
|
|
| `clear_lights()` | empties the list — only ambient will light the scene (useful for a flat look without switching to unlit) |
|
|
| `set_lights(Lights)` | replaces the whole list (batch reset) |
|
|
| `lights()` | reads the current list |
|
|
|
|
## ⚠️ Packed indices (important for shadows)
|
|
|
|
Lights are stacked in the GPU array **by type, in order**:
|
|
|
|
```
|
|
index 0 .. n_dir-1 : directional
|
|
index n_dir .. +n_point-1 : point
|
|
index … .. +n_spot-1 : spot
|
|
```
|
|
|
|
Two consequences:
|
|
|
|
1. **Index 0 is the default +Z directional** (the one `Lights::new()` pre-loads),
|
|
not your first added light. This is a classic pitfall — see
|
|
[Shadows](shadows.md).
|
|
2. If you want **your** light to be the only one (and thus at index 0), clear the list
|
|
first: `app.scene.clear_lights();` then `add_*_light(…)` (this is the technique in
|
|
[`shadow_test.rs`](../../lib/examples/shadow_test.rs)).
|
|
|
|
## Intensities and tints
|
|
|
|
- `color` is an RGB in `[0..1]`; `intensity` is an unbounded multiplier.
|
|
- Local lights (point/spot) attenuate **linearly** — intensity drops to zero at `radius`.
|
|
Beyond the radius, the light contributes nothing.
|
|
- The `standard` shader accumulates ambient + all lights (no mutual occlusion between
|
|
lights; the spot cone culling happens at the fragment).
|
|
|
|
## Links
|
|
|
|
- [User README](README.md) · [Shadows](shadows.md) · [Materials & textures](materials.md)
|
|
- [Root README](../../README.md) · [ARCHI_RENDU](../tech/ARCHI_RENDU.md)
|