Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_anti_alias/src/fxaa/mod.rs
9416 views
1
use bevy_app::prelude::*;
2
use bevy_asset::{embedded_asset, load_embedded_asset, AssetServer, Handle};
3
use bevy_camera::Camera;
4
use bevy_core_pipeline::{
5
schedule::{Core2d, Core2dSystems, Core3d, Core3dSystems},
6
tonemapping::tonemapping,
7
FullscreenShader,
8
};
9
use bevy_ecs::prelude::*;
10
use bevy_image::BevyDefault as _;
11
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
12
use bevy_render::{
13
extract_component::{ExtractComponent, ExtractComponentPlugin},
14
render_resource::{
15
binding_types::{sampler, texture_2d},
16
*,
17
},
18
renderer::RenderDevice,
19
view::{ExtractedView, ViewTarget},
20
Render, RenderApp, RenderStartup, RenderSystems,
21
};
22
use bevy_shader::Shader;
23
use bevy_utils::default;
24
25
mod node;
26
27
pub(crate) use node::fxaa;
28
29
#[derive(Debug, Reflect, Eq, PartialEq, Hash, Clone, Copy)]
30
#[reflect(PartialEq, Hash, Clone)]
31
pub enum Sensitivity {
32
Low,
33
Medium,
34
High,
35
Ultra,
36
Extreme,
37
}
38
39
impl Sensitivity {
40
pub fn get_str(&self) -> &str {
41
match self {
42
Sensitivity::Low => "LOW",
43
Sensitivity::Medium => "MEDIUM",
44
Sensitivity::High => "HIGH",
45
Sensitivity::Ultra => "ULTRA",
46
Sensitivity::Extreme => "EXTREME",
47
}
48
}
49
}
50
51
/// A component for enabling Fast Approximate Anti-Aliasing (FXAA)
52
/// for a [`bevy_camera::Camera`].
53
#[derive(Reflect, Component, Clone, ExtractComponent)]
54
#[reflect(Component, Default, Clone)]
55
#[extract_component_filter(With<Camera>)]
56
#[doc(alias = "FastApproximateAntiAliasing")]
57
pub struct Fxaa {
58
/// Enable render passes for FXAA.
59
pub enabled: bool,
60
61
/// Use lower sensitivity for a sharper, faster, result.
62
/// Use higher sensitivity for a slower, smoother, result.
63
/// [`Ultra`](`Sensitivity::Ultra`) and [`Extreme`](`Sensitivity::Extreme`)
64
/// settings can result in significant smearing and loss of detail.
65
///
66
/// The minimum amount of local contrast required to apply algorithm.
67
pub edge_threshold: Sensitivity,
68
69
/// Trims the algorithm from processing darks.
70
pub edge_threshold_min: Sensitivity,
71
}
72
73
impl Default for Fxaa {
74
fn default() -> Self {
75
Fxaa {
76
enabled: true,
77
edge_threshold: Sensitivity::High,
78
edge_threshold_min: Sensitivity::High,
79
}
80
}
81
}
82
83
/// Adds support for Fast Approximate Anti-Aliasing (FXAA)
84
#[derive(Default)]
85
pub struct FxaaPlugin;
86
impl Plugin for FxaaPlugin {
87
fn build(&self, app: &mut App) {
88
embedded_asset!(app, "fxaa.wgsl");
89
90
app.add_plugins(ExtractComponentPlugin::<Fxaa>::default());
91
92
let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
93
return;
94
};
95
render_app
96
.init_resource::<SpecializedRenderPipelines<FxaaPipeline>>()
97
.add_systems(RenderStartup, init_fxaa_pipeline)
98
.add_systems(
99
Render,
100
prepare_fxaa_pipelines.in_set(RenderSystems::Prepare),
101
)
102
.add_systems(
103
Core3d,
104
fxaa.after(tonemapping).in_set(Core3dSystems::PostProcess),
105
)
106
.add_systems(
107
Core2d,
108
fxaa.after(tonemapping).in_set(Core2dSystems::PostProcess),
109
);
110
}
111
}
112
113
#[derive(Resource)]
114
pub struct FxaaPipeline {
115
texture_bind_group: BindGroupLayoutDescriptor,
116
sampler: Sampler,
117
fullscreen_shader: FullscreenShader,
118
fragment_shader: Handle<Shader>,
119
}
120
121
pub fn init_fxaa_pipeline(
122
mut commands: Commands,
123
render_device: Res<RenderDevice>,
124
fullscreen_shader: Res<FullscreenShader>,
125
asset_server: Res<AssetServer>,
126
) {
127
let texture_bind_group = BindGroupLayoutDescriptor::new(
128
"fxaa_texture_bind_group_layout",
129
&BindGroupLayoutEntries::sequential(
130
ShaderStages::FRAGMENT,
131
(
132
texture_2d(TextureSampleType::Float { filterable: true }),
133
sampler(SamplerBindingType::Filtering),
134
),
135
),
136
);
137
138
let sampler = render_device.create_sampler(&SamplerDescriptor {
139
mipmap_filter: MipmapFilterMode::Linear,
140
mag_filter: FilterMode::Linear,
141
min_filter: FilterMode::Linear,
142
..default()
143
});
144
145
commands.insert_resource(FxaaPipeline {
146
texture_bind_group,
147
sampler,
148
fullscreen_shader: fullscreen_shader.clone(),
149
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "fxaa.wgsl"),
150
});
151
}
152
153
#[derive(Component)]
154
pub struct CameraFxaaPipeline {
155
pub pipeline_id: CachedRenderPipelineId,
156
}
157
158
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
159
pub struct FxaaPipelineKey {
160
edge_threshold: Sensitivity,
161
edge_threshold_min: Sensitivity,
162
texture_format: TextureFormat,
163
}
164
165
impl SpecializedRenderPipeline for FxaaPipeline {
166
type Key = FxaaPipelineKey;
167
168
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
169
RenderPipelineDescriptor {
170
label: Some("fxaa".into()),
171
layout: vec![self.texture_bind_group.clone()],
172
vertex: self.fullscreen_shader.to_vertex_state(),
173
fragment: Some(FragmentState {
174
shader: self.fragment_shader.clone(),
175
shader_defs: vec![
176
format!("EDGE_THRESH_{}", key.edge_threshold.get_str()).into(),
177
format!("EDGE_THRESH_MIN_{}", key.edge_threshold_min.get_str()).into(),
178
],
179
targets: vec![Some(ColorTargetState {
180
format: key.texture_format,
181
blend: None,
182
write_mask: ColorWrites::ALL,
183
})],
184
..default()
185
}),
186
..default()
187
}
188
}
189
}
190
191
pub fn prepare_fxaa_pipelines(
192
mut commands: Commands,
193
pipeline_cache: Res<PipelineCache>,
194
mut pipelines: ResMut<SpecializedRenderPipelines<FxaaPipeline>>,
195
fxaa_pipeline: Res<FxaaPipeline>,
196
views: Query<(Entity, &ExtractedView, &Fxaa)>,
197
) {
198
for (entity, view, fxaa) in &views {
199
if !fxaa.enabled {
200
continue;
201
}
202
let pipeline_id = pipelines.specialize(
203
&pipeline_cache,
204
&fxaa_pipeline,
205
FxaaPipelineKey {
206
edge_threshold: fxaa.edge_threshold,
207
edge_threshold_min: fxaa.edge_threshold_min,
208
texture_format: if view.hdr {
209
ViewTarget::TEXTURE_FORMAT_HDR
210
} else {
211
TextureFormat::bevy_default()
212
},
213
},
214
);
215
216
commands
217
.entity(entity)
218
.insert(CameraFxaaPipeline { pipeline_id });
219
}
220
}
221
222