Skip to content

FogVolumes silently render nothing when no VolumetricLight exists in the scene #25284

Description

@blaind

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:

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:

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::<FogVolume>();
    }
    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 VolumetricLights (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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-RenderingDrawing game state to the screenC-BugAn unexpected or incorrect behaviorS-Ready-For-ImplementationThis issue is ready for an implementation PR. Go for it!

    Type

    No type

    Projects

    Status
    Needs SME Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions