AdapterInfo { name: "NVIDIA GeForce RTX 3090", vendor: 4318, device: 8708, device_type: DiscreteGpu, device_pci_bus_id: "0000:09:00.0", driver: "NVIDIA", driver_info: "595.58.03", backend: Vulkan, subgroup_min_size: 32, subgroup_max_size: 32, transient_saves_memory: false }
Create a simple scene with a volumetric spotlight, pointlight, ground plane and sphere encapsulated in a fog volume.
//! Demonstrates volumetric fog and lighting (light shafts or god rays).
//! Note: On Wasm, this example only runs on WebGPU
#[cfg(feature = "free_camera")]
use bevy::camera_controller::free_camera::{FreeCamera, FreeCameraPlugin};
use bevy::{
color::palettes::css::RED,
core_pipeline::tonemapping::Tonemapping,
light::{FogVolume, VolumetricFog, VolumetricLight},
math::vec3,
post_process::bloom::Bloom,
prelude::*,
};
/// The current settings that the user has chosen.
#[derive(Resource)]
struct AppSettings {
/// Whether volumetric spot light is on.
volumetric_spotlight: bool,
/// Whether volumetric point light is on.
volumetric_pointlight: bool,
}
impl Default for AppSettings {
fn default() -> Self {
Self {
volumetric_spotlight: true,
volumetric_pointlight: true,
}
}
}
fn main() {
App::new()
.add_plugins((DefaultPlugins,
#[cfg(feature = "free_camera")]
FreeCameraPlugin))
.insert_resource(ClearColor(Color::Srgba(Srgba {
red: 0.02,
green: 0.02,
blue: 0.02,
alpha: 1.0,
})))
.insert_resource(GlobalAmbientLight::NONE)
.init_resource::<AppSettings>()
.add_systems(Startup, setup)
// .add_systems(Update, adjust_app_settings)
.run();
}
/// Initializes the scene.
fn setup(mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>) {
// Spawn the camera.
commands
.spawn((
Camera3d::default(),
Transform::from_xyz(-10.0, 0.0, 0.0).looking_at(vec3(0.0, 0.0, 0.0), Vec3::Y),
Tonemapping::TonyMcMapface,
#[cfg(feature = "free_camera")]
FreeCamera::default(),
Bloom::default(),
))
.insert(VolumetricFog {
ambient_intensity: 0.0,
..default()
});
let material_red = materials.add(StandardMaterial {
base_color: Color::srgb_u8(255, 50, 50),
..default()
});
let material_white = materials.add(StandardMaterial {
base_color: Color::WHITE,
..default()
});
commands.spawn((
Transform::from_xyz(0.0, 0.0, 0.0),
Mesh3d(meshes.add(Sphere::new(1.0))),
MeshMaterial3d(material_red)
));
commands.spawn((
Transform::from_xyz(0.0, -1.0, 0.0),
Mesh3d(meshes.add(Plane3d::new(vec3(0.0, 1.0, 0.0), vec2(10.0, 10.0)))),
MeshMaterial3d(material_white)
));
commands.spawn((
Transform::from_xyz(0.4, 1.9, -1.0),
PointLight {
shadow_maps_enabled: true,
range: 150.0,
color: RED.into(),
intensity: 50_000.0,
..default()
},
VolumetricLight,
));
// commands.spawn((
// // Transform::from_rotation(),
// Transform::from_xyz(-1.8, 3.9, -2.7).looking_at(Vec3::ZERO, Vec3::Y),
// DirectionalLight {
// shadow_maps_enabled: true,
// ..default()
// },
// VolumetricLight,
// ));
// Add the spot light
commands.spawn((
Transform::from_xyz(-1.8, 3.9, -2.7).looking_at(Vec3::ZERO, Vec3::Y),
SpotLight {
intensity: 150_000.0, // lumens
color: Color::WHITE,
shadow_maps_enabled: true,
inner_angle: 0.76,
outer_angle: 0.94,
..default()
},
VolumetricLight,
));
// Add the fog volume.
commands.spawn((
FogVolume::default(),
Transform::from_scale(Vec3::splat(15.0)),
));
}
The spot light's volumetric shadow is behaving incorrectly. Note how the white light of the spotlight bleeds through the ground plane while the red light of the pointlight does not:
Same scene from another angle: Look at how the volumetric fog of the spotlight is cut-off at a weird angle, this doesn't happen for the point light. I know that this cutoff is in fact the shadow cast by the plane since it goes away when I remove the plane.

This makes me think the plane's orientation is assumed to be in the local coordinate space of the spotlight instead of in world-space.
Bevy version and features
0.19-dev (main)
[Optional] Relevant system information
What you did
Create a simple scene with a volumetric spotlight, pointlight, ground plane and sphere encapsulated in a fog volume.
What went wrong
The spot light's volumetric shadow is behaving incorrectly. Note how the white light of the spotlight bleeds through the ground plane while the red light of the pointlight does not:
Same scene from another angle: Look at how the volumetric fog of the spotlight is cut-off at a weird angle, this doesn't happen for the point light. I know that this cutoff is in fact the shadow cast by the plane since it goes away when I remove the plane.

When the spot light is pointed straight-down the issues go away:
This makes me think the plane's orientation is assumed to be in the local coordinate space of the spotlight instead of in world-space.