Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/3d/anti_aliasing.rs
6849 views
1
//! Compares different anti-aliasing techniques supported by Bevy.
2
3
use std::{f32::consts::PI, fmt::Write};
4
5
use 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")))]
25
use bevy::anti_alias::dlss::{
26
Dlss, DlssPerfQualityMode, DlssProjectId, DlssSuperResolutionSupported,
27
};
28
29
fn 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" // Don't copy paste this - generate your own UUID!
35
)));
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
47
type TaaComponents = (
48
TemporalAntiAliasing,
49
TemporalJitter,
50
MipBias,
51
DepthPrepass,
52
MotionVectorPrepass,
53
);
54
55
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
56
type DlssComponents = (
57
Dlss,
58
TemporalJitter,
59
MipBias,
60
DepthPrepass,
61
MotionVectorPrepass,
62
);
63
#[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
64
type DlssComponents = ();
65
66
fn 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
// No AA
101
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
// MSAA
111
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
// MSAA Sample Count
122
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
// FXAA
135
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
// FXAA Settings
145
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
// SMAA
169
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
// SMAA Settings
179
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
// TAA
195
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
// DLSS
205
#[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
// DLSS Settings
216
#[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
239
fn 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
263
fn 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
281
fn 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
411
/// Set up a simple 3D scene
412
fn 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
// Plane
420
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
// Cubes
431
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
// Flight Helmet
440
commands.spawn(SceneRoot(asset_server.load(
441
GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf"),
442
)));
443
444
// Light
445
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
// Camera
461
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
// example instructions
486
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
497
/// Writes a simple menu item that can be on or off.
498
fn 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
503
/// Creates a colorful test pattern
504
fn 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
}
533
534