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