1use std::{f32::consts::PI, fmt::Write};
4
5use bevy::{
6 anti_alias::{
7 contrast_adaptive_sharpening::ContrastAdaptiveSharpening,
8 fxaa::{Fxaa, Sensitivity},
9 smaa::{Smaa, SmaaPreset},
10 taa::TemporalAntiAliasing,
11 },
12 asset::RenderAssetUsages,
13 core_pipeline::prepass::{DepthPrepass, MotionVectorPrepass},
14 image::{ImageSampler, ImageSamplerDescriptor},
15 light::CascadeShadowConfigBuilder,
16 prelude::*,
17 render::{
18 camera::{MipBias, TemporalJitter},
19 render_resource::{Extent3d, TextureDimension, TextureFormat},
20 view::Hdr,
21 },
22};
23
24#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
25use bevy::anti_alias::dlss::{
26 Dlss, DlssPerfQualityMode, DlssProjectId, DlssSuperResolutionSupported,
27};
28
29fn main() {
30 let mut app = App::new();
31
32 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
33 app.insert_resource(DlssProjectId(bevy_asset::uuid::uuid!(
34 "5417916c-0291-4e3f-8f65-326c1858ab96" )));
36
37 app.add_plugins(DefaultPlugins)
38 .add_systems(Startup, setup)
39 .add_systems(
40 Update,
41 (modify_aa, modify_sharpening, modify_projection, update_ui),
42 );
43
44 app.run();
45}
46
47type TaaComponents = (
48 TemporalAntiAliasing,
49 TemporalJitter,
50 MipBias,
51 DepthPrepass,
52 MotionVectorPrepass,
53);
54
55#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
56type DlssComponents = (
57 Dlss,
58 TemporalJitter,
59 MipBias,
60 DepthPrepass,
61 MotionVectorPrepass,
62);
63#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
64type DlssComponents = ();
65
66fn modify_aa(
67 keys: Res<ButtonInput<KeyCode>>,
68 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] camera: Single<
69 (
70 Entity,
71 Option<&mut Fxaa>,
72 Option<&mut Smaa>,
73 Option<&TemporalAntiAliasing>,
74 &mut Msaa,
75 Option<&mut Dlss>,
76 ),
77 With<Camera>,
78 >,
79 #[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))] camera: Single<
80 (
81 Entity,
82 Option<&mut Fxaa>,
83 Option<&mut Smaa>,
84 Option<&TemporalAntiAliasing>,
85 &mut Msaa,
86 ),
87 With<Camera>,
88 >,
89 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] dlss_supported: Option<
90 Res<DlssSuperResolutionSupported>,
91 >,
92 mut commands: Commands,
93) {
94 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
95 let (camera_entity, fxaa, smaa, taa, mut msaa, dlss) = camera.into_inner();
96 #[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
97 let (camera_entity, fxaa, smaa, taa, mut msaa) = camera.into_inner();
98 let mut camera = commands.entity(camera_entity);
99
100 if keys.just_pressed(KeyCode::Digit1) {
102 *msaa = Msaa::Off;
103 camera
104 .remove::<Fxaa>()
105 .remove::<Smaa>()
106 .remove::<TaaComponents>()
107 .remove::<DlssComponents>();
108 }
109
110 if keys.just_pressed(KeyCode::Digit2) && *msaa == Msaa::Off {
112 camera
113 .remove::<Fxaa>()
114 .remove::<Smaa>()
115 .remove::<TaaComponents>()
116 .remove::<DlssComponents>();
117
118 *msaa = Msaa::Sample4;
119 }
120
121 if *msaa != Msaa::Off {
123 if keys.just_pressed(KeyCode::KeyQ) {
124 *msaa = Msaa::Sample2;
125 }
126 if keys.just_pressed(KeyCode::KeyW) {
127 *msaa = Msaa::Sample4;
128 }
129 if keys.just_pressed(KeyCode::KeyE) {
130 *msaa = Msaa::Sample8;
131 }
132 }
133
134 if keys.just_pressed(KeyCode::Digit3) && fxaa.is_none() {
136 *msaa = Msaa::Off;
137 camera
138 .remove::<Smaa>()
139 .remove::<TaaComponents>()
140 .remove::<DlssComponents>()
141 .insert(Fxaa::default());
142 }
143
144 if let Some(mut fxaa) = fxaa {
146 if keys.just_pressed(KeyCode::KeyQ) {
147 fxaa.edge_threshold = Sensitivity::Low;
148 fxaa.edge_threshold_min = Sensitivity::Low;
149 }
150 if keys.just_pressed(KeyCode::KeyW) {
151 fxaa.edge_threshold = Sensitivity::Medium;
152 fxaa.edge_threshold_min = Sensitivity::Medium;
153 }
154 if keys.just_pressed(KeyCode::KeyE) {
155 fxaa.edge_threshold = Sensitivity::High;
156 fxaa.edge_threshold_min = Sensitivity::High;
157 }
158 if keys.just_pressed(KeyCode::KeyR) {
159 fxaa.edge_threshold = Sensitivity::Ultra;
160 fxaa.edge_threshold_min = Sensitivity::Ultra;
161 }
162 if keys.just_pressed(KeyCode::KeyT) {
163 fxaa.edge_threshold = Sensitivity::Extreme;
164 fxaa.edge_threshold_min = Sensitivity::Extreme;
165 }
166 }
167
168 if keys.just_pressed(KeyCode::Digit4) && smaa.is_none() {
170 *msaa = Msaa::Off;
171 camera
172 .remove::<Fxaa>()
173 .remove::<TaaComponents>()
174 .remove::<DlssComponents>()
175 .insert(Smaa::default());
176 }
177
178 if let Some(mut smaa) = smaa {
180 if keys.just_pressed(KeyCode::KeyQ) {
181 smaa.preset = SmaaPreset::Low;
182 }
183 if keys.just_pressed(KeyCode::KeyW) {
184 smaa.preset = SmaaPreset::Medium;
185 }
186 if keys.just_pressed(KeyCode::KeyE) {
187 smaa.preset = SmaaPreset::High;
188 }
189 if keys.just_pressed(KeyCode::KeyR) {
190 smaa.preset = SmaaPreset::Ultra;
191 }
192 }
193
194 if keys.just_pressed(KeyCode::Digit5) && taa.is_none() {
196 *msaa = Msaa::Off;
197 camera
198 .remove::<Fxaa>()
199 .remove::<Smaa>()
200 .remove::<DlssComponents>()
201 .insert(TemporalAntiAliasing::default());
202 }
203
204 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
206 if keys.just_pressed(KeyCode::Digit6) && dlss.is_none() && dlss_supported.is_some() {
207 *msaa = Msaa::Off;
208 camera
209 .remove::<Fxaa>()
210 .remove::<Smaa>()
211 .remove::<TaaComponents>()
212 .insert(Dlss::default());
213 }
214
215 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
217 if let Some(mut dlss) = dlss {
218 if keys.just_pressed(KeyCode::KeyZ) {
219 dlss.perf_quality_mode = DlssPerfQualityMode::Auto;
220 }
221 if keys.just_pressed(KeyCode::KeyX) {
222 dlss.perf_quality_mode = DlssPerfQualityMode::UltraPerformance;
223 }
224 if keys.just_pressed(KeyCode::KeyC) {
225 dlss.perf_quality_mode = DlssPerfQualityMode::Performance;
226 }
227 if keys.just_pressed(KeyCode::KeyV) {
228 dlss.perf_quality_mode = DlssPerfQualityMode::Balanced;
229 }
230 if keys.just_pressed(KeyCode::KeyB) {
231 dlss.perf_quality_mode = DlssPerfQualityMode::Quality;
232 }
233 if keys.just_pressed(KeyCode::KeyN) {
234 dlss.perf_quality_mode = DlssPerfQualityMode::Dlaa;
235 }
236 }
237}
238
239fn modify_sharpening(
240 keys: Res<ButtonInput<KeyCode>>,
241 mut query: Query<&mut ContrastAdaptiveSharpening>,
242) {
243 for mut cas in &mut query {
244 if keys.just_pressed(KeyCode::Digit0) {
245 cas.enabled = !cas.enabled;
246 }
247 if cas.enabled {
248 if keys.just_pressed(KeyCode::Minus) {
249 cas.sharpening_strength -= 0.1;
250 cas.sharpening_strength = cas.sharpening_strength.clamp(0.0, 1.0);
251 }
252 if keys.just_pressed(KeyCode::Equal) {
253 cas.sharpening_strength += 0.1;
254 cas.sharpening_strength = cas.sharpening_strength.clamp(0.0, 1.0);
255 }
256 if keys.just_pressed(KeyCode::KeyD) {
257 cas.denoise = !cas.denoise;
258 }
259 }
260 }
261}
262
263fn modify_projection(keys: Res<ButtonInput<KeyCode>>, mut query: Query<&mut Projection>) {
264 for mut projection in &mut query {
265 if keys.just_pressed(KeyCode::KeyO) {
266 match *projection {
267 Projection::Perspective(_) => {
268 *projection = Projection::Orthographic(OrthographicProjection {
269 scale: 0.002,
270 ..OrthographicProjection::default_3d()
271 });
272 }
273 _ => {
274 *projection = Projection::Perspective(PerspectiveProjection::default());
275 }
276 }
277 }
278 }
279}
280
281fn update_ui(
282 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] camera: Single<
283 (
284 &Projection,
285 Option<&Fxaa>,
286 Option<&Smaa>,
287 Option<&TemporalAntiAliasing>,
288 &ContrastAdaptiveSharpening,
289 &Msaa,
290 Option<&Dlss>,
291 ),
292 With<Camera>,
293 >,
294 #[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))] camera: Single<
295 (
296 &Projection,
297 Option<&Fxaa>,
298 Option<&Smaa>,
299 Option<&TemporalAntiAliasing>,
300 &ContrastAdaptiveSharpening,
301 &Msaa,
302 ),
303 With<Camera>,
304 >,
305 mut ui: Single<&mut Text>,
306 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] dlss_supported: Option<
307 Res<DlssSuperResolutionSupported>,
308 >,
309) {
310 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
311 let (projection, fxaa, smaa, taa, cas, msaa, dlss) = *camera;
312 #[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
313 let (projection, fxaa, smaa, taa, cas, msaa) = *camera;
314
315 let ui = &mut ui.0;
316 *ui = "Antialias Method\n".to_string();
317
318 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
319 let dlss_none = dlss.is_none();
320 #[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
321 let dlss_none = true;
322
323 draw_selectable_menu_item(
324 ui,
325 "No AA",
326 '1',
327 *msaa == Msaa::Off && fxaa.is_none() && taa.is_none() && smaa.is_none() && dlss_none,
328 );
329 draw_selectable_menu_item(ui, "MSAA", '2', *msaa != Msaa::Off);
330 draw_selectable_menu_item(ui, "FXAA", '3', fxaa.is_some());
331 draw_selectable_menu_item(ui, "SMAA", '4', smaa.is_some());
332 draw_selectable_menu_item(ui, "TAA", '5', taa.is_some());
333 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
334 if dlss_supported.is_some() {
335 draw_selectable_menu_item(ui, "DLSS", '6', dlss.is_some());
336 }
337
338 if *msaa != Msaa::Off {
339 ui.push_str("\n----------\n\nSample Count\n");
340 draw_selectable_menu_item(ui, "2", 'Q', *msaa == Msaa::Sample2);
341 draw_selectable_menu_item(ui, "4", 'W', *msaa == Msaa::Sample4);
342 draw_selectable_menu_item(ui, "8", 'E', *msaa == Msaa::Sample8);
343 }
344
345 if let Some(fxaa) = fxaa {
346 ui.push_str("\n----------\n\nSensitivity\n");
347 draw_selectable_menu_item(ui, "Low", 'Q', fxaa.edge_threshold == Sensitivity::Low);
348 draw_selectable_menu_item(
349 ui,
350 "Medium",
351 'W',
352 fxaa.edge_threshold == Sensitivity::Medium,
353 );
354 draw_selectable_menu_item(ui, "High", 'E', fxaa.edge_threshold == Sensitivity::High);
355 draw_selectable_menu_item(ui, "Ultra", 'R', fxaa.edge_threshold == Sensitivity::Ultra);
356 draw_selectable_menu_item(
357 ui,
358 "Extreme",
359 'T',
360 fxaa.edge_threshold == Sensitivity::Extreme,
361 );
362 }
363
364 if let Some(smaa) = smaa {
365 ui.push_str("\n----------\n\nQuality\n");
366 draw_selectable_menu_item(ui, "Low", 'Q', smaa.preset == SmaaPreset::Low);
367 draw_selectable_menu_item(ui, "Medium", 'W', smaa.preset == SmaaPreset::Medium);
368 draw_selectable_menu_item(ui, "High", 'E', smaa.preset == SmaaPreset::High);
369 draw_selectable_menu_item(ui, "Ultra", 'R', smaa.preset == SmaaPreset::Ultra);
370 }
371
372 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
373 if let Some(dlss) = dlss {
374 let pqm = dlss.perf_quality_mode;
375 ui.push_str("\n----------\n\nQuality\n");
376 draw_selectable_menu_item(ui, "Auto", 'Z', pqm == DlssPerfQualityMode::Auto);
377 draw_selectable_menu_item(
378 ui,
379 "UltraPerformance",
380 'X',
381 pqm == DlssPerfQualityMode::UltraPerformance,
382 );
383 draw_selectable_menu_item(
384 ui,
385 "Performance",
386 'C',
387 pqm == DlssPerfQualityMode::Performance,
388 );
389 draw_selectable_menu_item(ui, "Balanced", 'V', pqm == DlssPerfQualityMode::Balanced);
390 draw_selectable_menu_item(ui, "Quality", 'B', pqm == DlssPerfQualityMode::Quality);
391 draw_selectable_menu_item(ui, "DLAA", 'N', pqm == DlssPerfQualityMode::Dlaa);
392 }
393
394 ui.push_str("\n----------\n\n");
395 draw_selectable_menu_item(ui, "Sharpening", '0', cas.enabled);
396
397 if cas.enabled {
398 ui.push_str(&format!("(-/+) Strength: {:.1}\n", cas.sharpening_strength));
399 draw_selectable_menu_item(ui, "Denoising", 'D', cas.denoise);
400 }
401
402 ui.push_str("\n----------\n\n");
403 draw_selectable_menu_item(
404 ui,
405 "Orthographic",
406 'O',
407 matches!(projection, Projection::Orthographic(_)),
408 );
409}
410
411fn setup(
413 mut commands: Commands,
414 mut meshes: ResMut<Assets<Mesh>>,
415 mut materials: ResMut<Assets<StandardMaterial>>,
416 mut images: ResMut<Assets<Image>>,
417 asset_server: Res<AssetServer>,
418) {
419 commands.spawn((
421 Mesh3d(meshes.add(Plane3d::default().mesh().size(20.0, 20.0))),
422 MeshMaterial3d(materials.add(Color::srgb(0.1, 0.2, 0.1))),
423 ));
424
425 let cube_material = materials.add(StandardMaterial {
426 base_color_texture: Some(images.add(uv_debug_texture())),
427 ..default()
428 });
429
430 for i in 0..5 {
432 commands.spawn((
433 Mesh3d(meshes.add(Cuboid::new(0.25, 0.25, 0.25))),
434 MeshMaterial3d(cube_material.clone()),
435 Transform::from_xyz(i as f32 * 0.25 - 1.0, 0.125, -i as f32 * 0.5),
436 ));
437 }
438
439 commands.spawn(SceneRoot(asset_server.load(
441 GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"),
442 )));
443
444 commands.spawn((
446 DirectionalLight {
447 illuminance: light_consts::lux::FULL_DAYLIGHT,
448 shadows_enabled: true,
449 ..default()
450 },
451 Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, PI * -0.15, PI * -0.15)),
452 CascadeShadowConfigBuilder {
453 maximum_distance: 3.0,
454 first_cascade_far_bound: 0.9,
455 ..default()
456 }
457 .build(),
458 ));
459
460 commands.spawn((
462 Camera3d::default(),
463 Hdr,
464 Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y),
465 ContrastAdaptiveSharpening {
466 enabled: false,
467 ..default()
468 },
469 EnvironmentMapLight {
470 diffuse_map: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"),
471 specular_map: asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
472 intensity: 150.0,
473 ..default()
474 },
475 DistanceFog {
476 color: Color::srgba_u8(43, 44, 47, 255),
477 falloff: FogFalloff::Linear {
478 start: 1.0,
479 end: 4.0,
480 },
481 ..default()
482 },
483 ));
484
485 commands.spawn((
487 Text::default(),
488 Node {
489 position_type: PositionType::Absolute,
490 top: px(12),
491 left: px(12),
492 ..default()
493 },
494 ));
495}
496
497fn draw_selectable_menu_item(ui: &mut String, label: &str, shortcut: char, enabled: bool) {
499 let star = if enabled { "*" } else { "" };
500 let _ = writeln!(*ui, "({shortcut}) {star}{label}{star}");
501}
502
503fn uv_debug_texture() -> Image {
505 const TEXTURE_SIZE: usize = 8;
506
507 let mut palette: [u8; 32] = [
508 255, 102, 159, 255, 255, 159, 102, 255, 236, 255, 102, 255, 121, 255, 102, 255, 102, 255,
509 198, 255, 102, 198, 255, 255, 121, 102, 255, 255, 236, 102, 255, 255,
510 ];
511
512 let mut texture_data = [0; TEXTURE_SIZE * TEXTURE_SIZE * 4];
513 for y in 0..TEXTURE_SIZE {
514 let offset = TEXTURE_SIZE * y * 4;
515 texture_data[offset..(offset + TEXTURE_SIZE * 4)].copy_from_slice(&palette);
516 palette.rotate_right(4);
517 }
518
519 let mut img = Image::new_fill(
520 Extent3d {
521 width: TEXTURE_SIZE as u32,
522 height: TEXTURE_SIZE as u32,
523 depth_or_array_layers: 1,
524 },
525 TextureDimension::D2,
526 &texture_data,
527 TextureFormat::Rgba8UnormSrgb,
528 RenderAssetUsages::RENDER_WORLD,
529 );
530 img.sampler = ImageSampler::Descriptor(ImageSamplerDescriptor::default());
531 img
532}