atmospheric_fog/
atmospheric_fog.rs

1//! This example showcases atmospheric fog
2//!
3//! ## Controls
4//!
5//! | Key Binding        | Action                                 |
6//! |:-------------------|:---------------------------------------|
7//! | `Spacebar`         | Toggle Atmospheric Fog                 |
8//! | `S`                | Toggle Directional Light Fog Influence |
9
10use bevy::{
11    light::{CascadeShadowConfigBuilder, NotShadowCaster},
12    prelude::*,
13};
14
15fn main() {
16    App::new()
17        .add_plugins(DefaultPlugins)
18        .add_systems(
19            Startup,
20            (setup_camera_fog, setup_terrain_scene, setup_instructions),
21        )
22        .add_systems(Update, toggle_system)
23        .run();
24}
25
26fn setup_camera_fog(mut commands: Commands) {
27    commands.spawn((
28        Camera3d::default(),
29        Transform::from_xyz(-1.0, 0.1, 1.0).looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
30        DistanceFog {
31            color: Color::srgba(0.35, 0.48, 0.66, 1.0),
32            directional_light_color: Color::srgba(1.0, 0.95, 0.85, 0.5),
33            directional_light_exponent: 30.0,
34            falloff: FogFalloff::from_visibility_colors(
35                15.0, // distance in world units up to which objects retain visibility (>= 5% contrast)
36                Color::srgb(0.35, 0.5, 0.66), // atmospheric extinction color (after light is lost due to absorption by atmospheric particles)
37                Color::srgb(0.8, 0.844, 1.0), // atmospheric inscattering color (light gained due to scattering from the sun)
38            ),
39        },
40    ));
41}
42
43fn setup_terrain_scene(
44    mut commands: Commands,
45    mut meshes: ResMut<Assets<Mesh>>,
46    mut materials: ResMut<Assets<StandardMaterial>>,
47    asset_server: Res<AssetServer>,
48) {
49    // Configure a properly scaled cascade shadow map for this scene (defaults are too large, mesh units are in km)
50    let cascade_shadow_config = CascadeShadowConfigBuilder {
51        first_cascade_far_bound: 0.3,
52        maximum_distance: 3.0,
53        ..default()
54    }
55    .build();
56
57    // Sun
58    commands.spawn((
59        DirectionalLight {
60            color: Color::srgb(0.98, 0.95, 0.82),
61            shadows_enabled: true,
62            ..default()
63        },
64        Transform::from_xyz(0.0, 0.0, 0.0).looking_at(Vec3::new(-0.15, -0.05, 0.25), Vec3::Y),
65        cascade_shadow_config,
66    ));
67
68    // Terrain
69    commands.spawn(SceneRoot(asset_server.load(
70        GltfAssetLabel::Scene(0).from_asset("models/terrain/Mountains.gltf"),
71    )));
72
73    // Sky
74    commands.spawn((
75        Mesh3d(meshes.add(Cuboid::new(2.0, 1.0, 1.0))),
76        MeshMaterial3d(materials.add(StandardMaterial {
77            base_color: Srgba::hex("888888").unwrap().into(),
78            unlit: true,
79            cull_mode: None,
80            ..default()
81        })),
82        Transform::from_scale(Vec3::splat(20.0)),
83        NotShadowCaster,
84    ));
85}
86
87fn setup_instructions(mut commands: Commands) {
88    commands.spawn((Text::new("Press Spacebar to Toggle Atmospheric Fog.\nPress S to Toggle Directional Light Fog Influence."),
89        Node {
90            position_type: PositionType::Absolute,
91            bottom: px(12),
92            left: px(12),
93            ..default()
94        })
95    );
96}
97
98fn toggle_system(keycode: Res<ButtonInput<KeyCode>>, mut fog: Single<&mut DistanceFog>) {
99    if keycode.just_pressed(KeyCode::Space) {
100        let a = fog.color.alpha();
101        fog.color.set_alpha(1.0 - a);
102    }
103
104    if keycode.just_pressed(KeyCode::KeyS) {
105        let a = fog.directional_light_color.alpha();
106        fog.directional_light_color.set_alpha(0.5 - a);
107    }
108}