117 lines
3.7 KiB
Rust
117 lines
3.7 KiB
Rust
//! 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<ProjectSettings>,
|
|
existing: Query<(), With<DirectionalLight>>,
|
|
scene_suns: Query<(&LightDesc, Option<&InspectorOrder>), With<LevelObject>>,
|
|
) {
|
|
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,
|
|
shadows_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<LevelObject>>,
|
|
mut project_suns: Query<(&mut DirectionalLight, &mut Visibility), With<ProjectSun>>,
|
|
) {
|
|
let scene_override = has_scene_sun_override(&scene_suns);
|
|
for (mut sun, mut visibility) in &mut project_suns {
|
|
sun.shadows_enabled = !scene_override;
|
|
*visibility = if scene_override {
|
|
Visibility::Hidden
|
|
} else {
|
|
Visibility::Visible
|
|
};
|
|
}
|
|
}
|
|
|
|
fn has_scene_sun_override(
|
|
scene_suns: &Query<(&LightDesc, Option<&InspectorOrder>), With<LevelObject>>,
|
|
) -> 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<ProjectSettings>,
|
|
mut project_suns: Query<&mut DirectionalLight, With<ProjectSun>>,
|
|
) {
|
|
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<ProjectSettings>,
|
|
mut scene_lights: Query<
|
|
&mut CascadeShadowConfig,
|
|
(
|
|
With<LevelObject>,
|
|
With<DirectionalLight>,
|
|
Without<ProjectSun>,
|
|
),
|
|
>,
|
|
) {
|
|
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<ProjectSettings>,
|
|
scene_suns: Query<(&LightDesc, Option<&InspectorOrder>), With<LevelObject>>,
|
|
mut project_suns: Query<(&mut DirectionalLight, &mut Visibility), With<ProjectSun>>,
|
|
) {
|
|
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.shadows_enabled = !scene_override;
|
|
*visibility = if scene_override {
|
|
Visibility::Hidden
|
|
} else {
|
|
Visibility::Visible
|
|
};
|
|
}
|
|
}
|