Volumetric point/spot light in-scatter vanishes in large `FogVolume`s
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## Bevy version and features
- v0.19.0 (default features, Linux x86_64, Vulkan)
## What you did
Built a foggy street scene: a world-scale `FogVolume` with street lamps and headlights as volumetric point/spot lights. Minimal form (ambient at 0 so the point light is the only fog illumination):
```rust
commands.spawn((
Camera3d::default(),
Hdr,
VolumetricFog {
ambient_intensity: 0.0,
..default()
},
Transform::from_xyz(0.0, 4.0, 16.0).looking_at(Vec3::new(0.0, 3.0, 0.0), Vec3::Y),
));
// A world-scale fog volume...
commands.spawn((
FogVolume {
density_factor: 0.15,
scattering: 0.6,
absorption: 0.05,
..default()
},
Transform::from_xyz(0.0, 5.0, -22.0).with_scale(Vec3::new(100.0, 20.0, 60.0)),
));
// ...swap the scale for Vec3::splat(4.0) and the same light below produces
// the expected glow ball.
// Shadow-mapped volumetric point light inside the fog.
commands.spawn((
PointLight {
intensity: 300_000.0,
range: 40.0,
shadow_maps_enabled: true,
..default()
},
VolumetricLight,
Transform::from_xyz(0.0, 2.5, 0.0),
));
```
Full runnable reproduction:
https://github.com/blaind/bevy-volumetric-ambient-repro (`MODE=pointlight`)
## What went wrong
- Expected: a glow ball around the light in both volume sizes.
- Actually: the 4x4x4 volume shows the expected glow; the 100x20x60 volume crushes the same light, same position, same intensity, to a barely visible pinprick.
Cause, in `crates/bevy_pbr/src/volumetric_fog/volumetric_fog.wgsl` (applied per raymarch step in the point/spot loop, and in the directional loop too):
```wgsl
let light_attenuation = exp(-density * bounding_radius * (absorption + scattering));
```
`bounding_radius` is the radius of the sphere bounding the **entire fog volume**, a constant. Every light at every sample is charged the cost of crossing the whole volume regardless of the actual light-to-sample distance, and the local sample density is extrapolated over that constant distance. For the large volume here: density 0.15 x radius ~59 x extinction 0.65 gives `exp(-5.75)`, 0.3% of the light's scatter. The falloff is exponential in volume size, so realistic-lumen punctual lights die completely at world scale; directional god rays survive in practice only because tens of thousands of lux have headroom.
## Additional information
- Suggested fix included in the repro as [`fix-punctual-light-fog-attenuation.patch`](https://github.com/blaind/bevy-volumetric-ambient-repro/blob/main/fix-punctual-light-fog-attenuation.patch)
4-unit volume: the expected glow ball:
100x20x60 volume, same light: the glow is crushed to a pinprick by the bounding-radius term:
same large volume with the fix: the light-to-sample distance replaces the bounding radius, and the glow returns
fix regression check: the small volume still renders a comparable glow ball:
Contributor guide
Research direction
Start in crates/bevy_pbr/src/volumetric_fog/volumetric_fog.wgsl and inspect the point/spot-light attenuation in the raymarch loop. Run the linked reproduction with MODE=pointlight, comparing the small and world-scale FogVolumes and the included fix-punctual-light-fog-attenuation.patch. Done means the large volume restores the point-light glow while the small volume remains comparable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- computer-graphics, game-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100