//! Outdoor lighting: a single directional sun with cascaded shadow maps. use bevy::light::CascadeShadowConfig; use bevy::prelude::*; use settings::ProjectSettings; use shared::{ cascade_config_from_rendering, inspector_component_active, AuthoringLightKind, InspectorOrder, LevelObject, LightDesc, ProjectSun, COMPONENT_LIGHT_DESC, }; /// Spawns the directional "sun" from project rendering settings. #[unsafe(no_mangle)] pub fn spawn_sun( mut commands: Commands, settings: Res, existing: Query<(), With>, scene_suns: Query<(&LightDesc, Option<&InspectorOrder>), With>, ) { if !existing.is_empty() { return; } let rendering = &settings.rendering; let cascades = cascade_config_from_rendering(rendering); commands.spawn(( Name::new("Sun"), ProjectSun, DirectionalLight { illuminance: rendering.sun_illuminance, shadow_maps_enabled: !has_scene_sun_override(&scene_suns), ..default() }, Visibility::default(), Transform::from_xyz(0.0, 0.0, 0.0).looking_to(Vec3::new(-0.35, -0.85, -0.4), Vec3::Y), cascades, )); } #[unsafe(no_mangle)] pub fn sync_project_sun_visibility( scene_suns: Query<(&LightDesc, Option<&InspectorOrder>), With>, mut project_suns: Query<(&mut DirectionalLight, &mut Visibility), With>, ) { let scene_override = has_scene_sun_override(&scene_suns); for (mut sun, mut visibility) in &mut project_suns { sun.shadow_maps_enabled = !scene_override; *visibility = if scene_override { Visibility::Hidden } else { Visibility::Visible }; } } fn has_scene_sun_override( scene_suns: &Query<(&LightDesc, Option<&InspectorOrder>), With>, ) -> bool { scene_suns.iter().any(|(light, order)| { inspector_component_active(order, COMPONENT_LIGHT_DESC) && matches!(light.kind, AuthoringLightKind::Directional) }) } /// Keeps the project sun's illuminance in sync with [`ProjectSettings`] when settings change. #[unsafe(no_mangle)] pub fn sync_project_sun_illuminance( settings: Res, mut project_suns: Query<&mut DirectionalLight, With>, ) { let illuminance = settings.rendering.sun_illuminance; for mut sun in &mut project_suns { sun.illuminance = illuminance; } } /// Keeps scene directional (non-[`ProjectSun`]) cascade configs aligned with project shadow settings. #[unsafe(no_mangle)] pub fn sync_scene_directional_shadow_cascades( settings: Res, mut scene_lights: Query< &mut CascadeShadowConfig, ( With, With, Without, ), >, ) { if !settings.is_changed() { return; } let cascades = cascade_config_from_rendering(&settings.rendering); for mut config in &mut scene_lights { *config = cascades.clone(); } } #[unsafe(no_mangle)] pub fn sync_project_sun_from_settings( settings: Res, scene_suns: Query<(&LightDesc, Option<&InspectorOrder>), With>, mut project_suns: Query<(&mut DirectionalLight, &mut Visibility), With>, ) { let scene_override = has_scene_sun_override(&scene_suns); let illuminance = settings.rendering.sun_illuminance; for (mut sun, mut visibility) in &mut project_suns { sun.illuminance = illuminance; sun.shadow_maps_enabled = !scene_override; *visibility = if scene_override { Visibility::Hidden } else { Visibility::Visible }; } }