1use bevy::{
25 light::{NotShadowCaster, NotShadowReceiver},
26 math::ops,
27 prelude::*,
28};
29
30fn main() {
31 App::new()
32 .insert_resource(AmbientLight::NONE)
33 .add_plugins(DefaultPlugins)
34 .add_systems(
35 Startup,
36 (setup_camera_fog, setup_pyramid_scene, setup_instructions),
37 )
38 .add_systems(Update, update_system)
39 .run();
40}
41
42fn setup_camera_fog(mut commands: Commands) {
43 commands.spawn((
44 Camera3d::default(),
45 DistanceFog {
46 color: Color::srgb(0.25, 0.25, 0.25),
47 falloff: FogFalloff::Linear {
48 start: 5.0,
49 end: 20.0,
50 },
51 ..default()
52 },
53 ));
54}
55
56fn setup_pyramid_scene(
57 mut commands: Commands,
58 mut meshes: ResMut<Assets<Mesh>>,
59 mut materials: ResMut<Assets<StandardMaterial>>,
60) {
61 let stone = materials.add(StandardMaterial {
62 base_color: Srgba::hex("28221B").unwrap().into(),
63 perceptual_roughness: 1.0,
64 ..default()
65 });
66
67 for (x, z) in &[(-1.5, -1.5), (1.5, -1.5), (1.5, 1.5), (-1.5, 1.5)] {
69 commands.spawn((
70 Mesh3d(meshes.add(Cuboid::new(1.0, 3.0, 1.0))),
71 MeshMaterial3d(stone.clone()),
72 Transform::from_xyz(*x, 1.5, *z),
73 ));
74 }
75
76 commands.spawn((
78 Mesh3d(meshes.add(Sphere::default())),
79 MeshMaterial3d(materials.add(StandardMaterial {
80 base_color: Srgba::hex("126212CC").unwrap().into(),
81 reflectance: 1.0,
82 perceptual_roughness: 0.0,
83 metallic: 0.5,
84 alpha_mode: AlphaMode::Blend,
85 ..default()
86 })),
87 Transform::from_scale(Vec3::splat(1.75)).with_translation(Vec3::new(0.0, 4.0, 0.0)),
88 NotShadowCaster,
89 NotShadowReceiver,
90 ));
91
92 for i in 0..50 {
94 let half_size = i as f32 / 2.0 + 3.0;
95 let y = -i as f32 / 2.0;
96 commands.spawn((
97 Mesh3d(meshes.add(Cuboid::new(2.0 * half_size, 0.5, 2.0 * half_size))),
98 MeshMaterial3d(stone.clone()),
99 Transform::from_xyz(0.0, y + 0.25, 0.0),
100 ));
101 }
102
103 commands.spawn((
105 Mesh3d(meshes.add(Cuboid::new(2.0, 1.0, 1.0))),
106 MeshMaterial3d(materials.add(StandardMaterial {
107 base_color: Srgba::hex("888888").unwrap().into(),
108 unlit: true,
109 cull_mode: None,
110 ..default()
111 })),
112 Transform::from_scale(Vec3::splat(1_000_000.0)),
113 ));
114
115 commands.spawn((
117 PointLight {
118 shadows_enabled: true,
119 ..default()
120 },
121 Transform::from_xyz(0.0, 1.0, 0.0),
122 ));
123}
124
125fn setup_instructions(mut commands: Commands) {
126 commands.spawn((
127 Text::default(),
128 Node {
129 position_type: PositionType::Absolute,
130 top: px(12),
131 left: px(12),
132 ..default()
133 },
134 ));
135}
136
137fn update_system(
138 camera: Single<(&mut DistanceFog, &mut Transform)>,
139 mut text: Single<&mut Text>,
140 time: Res<Time>,
141 keycode: Res<ButtonInput<KeyCode>>,
142) {
143 let now = time.elapsed_secs();
144 let delta = time.delta_secs();
145
146 let (mut fog, mut transform) = camera.into_inner();
147
148 let orbit_scale = 8.0 + ops::sin(now / 10.0) * 7.0;
150 *transform = Transform::from_xyz(
151 ops::cos(now / 5.0) * orbit_scale,
152 12.0 - orbit_scale / 2.0,
153 ops::sin(now / 5.0) * orbit_scale,
154 )
155 .looking_at(Vec3::ZERO, Vec3::Y);
156
157 text.0 = format!("Fog Falloff: {:?}\nFog Color: {:?}", fog.falloff, fog.color);
159
160 text.push_str("\n\n1 / 2 / 3 - Fog Falloff Mode");
162
163 if keycode.pressed(KeyCode::Digit1) {
164 if let FogFalloff::Linear { .. } = fog.falloff {
165 } else {
167 fog.falloff = FogFalloff::Linear {
168 start: 5.0,
169 end: 20.0,
170 };
171 };
172 }
173
174 if keycode.pressed(KeyCode::Digit2) {
175 if let FogFalloff::Exponential { .. } = fog.falloff {
176 } else if let FogFalloff::ExponentialSquared { density } = fog.falloff {
178 fog.falloff = FogFalloff::Exponential { density };
179 } else {
180 fog.falloff = FogFalloff::Exponential { density: 0.07 };
181 };
182 }
183
184 if keycode.pressed(KeyCode::Digit3) {
185 if let FogFalloff::Exponential { density } = fog.falloff {
186 fog.falloff = FogFalloff::ExponentialSquared { density };
187 } else if let FogFalloff::ExponentialSquared { .. } = fog.falloff {
188 } else {
190 fog.falloff = FogFalloff::ExponentialSquared { density: 0.07 };
191 };
192 }
193
194 if let FogFalloff::Linear { start, end } = &mut fog.falloff {
196 text.push_str("\nA / S - Move Start Distance\nZ / X - Move End Distance");
197
198 if keycode.pressed(KeyCode::KeyA) {
199 *start -= delta * 3.0;
200 }
201 if keycode.pressed(KeyCode::KeyS) {
202 *start += delta * 3.0;
203 }
204 if keycode.pressed(KeyCode::KeyZ) {
205 *end -= delta * 3.0;
206 }
207 if keycode.pressed(KeyCode::KeyX) {
208 *end += delta * 3.0;
209 }
210 }
211
212 if let FogFalloff::Exponential { density } = &mut fog.falloff {
214 text.push_str("\nA / S - Change Density");
215
216 if keycode.pressed(KeyCode::KeyA) {
217 *density -= delta * 0.5 * *density;
218 if *density < 0.0 {
219 *density = 0.0;
220 }
221 }
222 if keycode.pressed(KeyCode::KeyS) {
223 *density += delta * 0.5 * *density;
224 }
225 }
226
227 if let FogFalloff::ExponentialSquared { density } = &mut fog.falloff {
229 text.push_str("\nA / S - Change Density");
230
231 if keycode.pressed(KeyCode::KeyA) {
232 *density -= delta * 0.5 * *density;
233 if *density < 0.0 {
234 *density = 0.0;
235 }
236 }
237 if keycode.pressed(KeyCode::KeyS) {
238 *density += delta * 0.5 * *density;
239 }
240 }
241
242 text.push_str("\n\n- / = - Red\n[ / ] - Green\n; / ' - Blue\n. / ? - Alpha");
244
245 let mut fog_color = Srgba::from(fog.color);
249 if keycode.pressed(KeyCode::Minus) {
250 fog_color.red = (fog_color.red - 0.1 * delta).max(0.0);
251 }
252
253 if keycode.any_pressed([KeyCode::Equal, KeyCode::NumpadEqual]) {
254 fog_color.red = (fog_color.red + 0.1 * delta).min(1.0);
255 }
256
257 if keycode.pressed(KeyCode::BracketLeft) {
258 fog_color.green = (fog_color.green - 0.1 * delta).max(0.0);
259 }
260
261 if keycode.pressed(KeyCode::BracketRight) {
262 fog_color.green = (fog_color.green + 0.1 * delta).min(1.0);
263 }
264
265 if keycode.pressed(KeyCode::Semicolon) {
266 fog_color.blue = (fog_color.blue - 0.1 * delta).max(0.0);
267 }
268
269 if keycode.pressed(KeyCode::Quote) {
270 fog_color.blue = (fog_color.blue + 0.1 * delta).min(1.0);
271 }
272
273 if keycode.pressed(KeyCode::Period) {
274 fog_color.alpha = (fog_color.alpha - 0.1 * delta).max(0.0);
275 }
276
277 if keycode.pressed(KeyCode::Slash) {
278 fog_color.alpha = (fog_color.alpha + 0.1 * delta).min(1.0);
279 }
280
281 fog.color = Color::from(fog_color);
282}