`FogVolume`s silently render nothing when no `VolumetricLight` exists in the scene
- 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
Tried to build ambient-only fog (overcast sky, no god rays): a `FogVolume`, a camera with `VolumetricFog`, and a directional light without the `VolumetricLight` marker:
```rust
commands.spawn((
Camera3d::default(),
Hdr,
VolumetricFog {
ambient_intensity: 8.0,
..default()
},
Transform::from_xyz(0.0, 4.0, 16.0).looking_at(Vec3::new(0.0, 3.0, 0.0), Vec3::Y),
));
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)),
));
// Note: no VolumetricLight anywhere in the scene.
commands.spawn((
DirectionalLight {
illuminance: 12000.0,
shadow_maps_enabled: false,
..default()
},
Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -1.0, 0.4, 0.0)),
));
```
Full runnable reproduction:
https://github.com/blaind/bevy-volumetric-ambient-repro (`MODE=nolight`)
## What went wrong
- Expected: fog lit by the ambient term, per the `FogVolume::fog_color` docs: "Note that the fog must be lit by a `VolumetricLight` **or ambient light** in order for this color to appear." At minimum, extinction.
- Actually: nothing renders at all. No in-scatter, no extinction. The screenshot is **byte-identical** (same sha256) to a render without working fog.
The gate is explicit in `crates/bevy_pbr/src/volumetric_fog/render.rs`, `extract_volumetric_fog`:
```rust
if volumetric_lights.is_empty() {
// TODO: needs better way to handle clean up in render world
for (entity, ..) in view_targets.iter() {
commands.entity(entity)
.remove::<(VolumetricFog, ViewVolumetricFogPipelines, ViewVolumetricFog)>();
}
for (entity, ..) in fog_volumes.iter() {
commands.entity(entity).remove::();
}
return;
}
```
So ambient-only fog cannot be expressed at all. The workaround is attaching `VolumetricLight` to a light that contributes nothing (e.g. a shadowless directional light), purely to activate the pass.
Possibly a design decision rather than a plain bug, but at least one of these seems warranted:
1. Run the pass when a `FogVolume` and a `VolumetricFog` camera exist, even with zero `VolumetricLight`s (extinction and ambient still apply), or
2. Fix the docs: `FogVolume::fog_color` currently promises ambient-only lighting works, and the `VolumetricFog` camera component doc (the natural docs.rs entry point) mentions neither the `FogVolume` nor the `VolumetricLight` requirement (it does document the WebGPU-on-Wasm requirement).
Contributor guide
Research direction
Start in crates/bevy_pbr/src/volumetric_fog/render.rs at extract_volumetric_fog and inspect the early return when volumetric_lights is empty. Use the linked ambient-only reproduction with MODE=nolight to compare behavior. Done means ambient-only FogVolume rendering follows the chosen behavior, including either working fog or corrected documentation.
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
- Mostly clear
- Newbie friendliness
- 55/100