Skip to content

Commit 47e7352

Browse files
Refactor the effect_stack post-processing module (#23928)
# Objective - I strongly agree with the doc style suggested by @mate-h in #23110. When I originally wrote the vignette docs, I just tried to match the style of the initial chromatic aberration comments without thinking too much about it. Now, I’ve updated them to be consistent with the current lens distortion docs. - I also made a few other minor changes to make the code cleaner. ## Solution - Merged Samplers: Replaced `source_sampler` and `chromatic_aberration_lut_sampler` with a single `common_sampler` (Both samplers are configured identically). - CPU-side Clamping: Moved mathematical bounds checks (e.g., clamp, max) from WGSL shaders into `prepare_post_processing_uniforms`. I only clamp values that would cause shader errors or result in unexpected behavior. - Unified Thresholds: Standardized the “skip post-processing” check to > 1e-4 for both `ChromaticAberration` and `Vignette ` extraction, avoiding unnecessary draw calls for negligible values. - Cleanup: Removed redundant `DEFAULT_*` constants in favor of inline literals in Default implementations. ## Testing - `post-processing` example works properly. ---
1 parent 6e7b436 commit 47e7352

6 files changed

Lines changed: 46 additions & 94 deletions

File tree

crates/bevy_post_process/src/effect_stack/chromatic_aberration.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ use bevy_render::{
2020
pub(super) static DEFAULT_CHROMATIC_ABERRATION_LUT_DATA: [u8; 12] =
2121
[255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255];
2222

23-
/// The default chromatic aberration intensity amount, in a fraction of the
24-
/// window size.
25-
const DEFAULT_CHROMATIC_ABERRATION_INTENSITY: f32 = 0.02;
26-
27-
/// The default maximum number of samples for chromatic aberration.
28-
const DEFAULT_CHROMATIC_ABERRATION_MAX_SAMPLES: u32 = 8;
29-
3023
#[derive(Resource)]
3124
pub(crate) struct DefaultChromaticAberrationLut(pub(crate) Handle<Image>);
3225

@@ -79,8 +72,8 @@ impl Default for ChromaticAberration {
7972
fn default() -> Self {
8073
Self {
8174
color_lut: None,
82-
intensity: DEFAULT_CHROMATIC_ABERRATION_INTENSITY,
83-
max_samples: DEFAULT_CHROMATIC_ABERRATION_MAX_SAMPLES,
75+
intensity: 0.02,
76+
max_samples: 8,
8477
}
8578
}
8679
}
@@ -97,8 +90,8 @@ impl ExtractComponent for ChromaticAberration {
9790
fn extract_component(
9891
chromatic_aberration: QueryItem<'_, '_, Self::QueryData>,
9992
) -> Option<Self::Out> {
100-
// Skip the postprocessing phase entirely if the intensity is zero.
101-
if chromatic_aberration.intensity > 0.0 {
93+
// Skip the postprocessing phase entirely if the intensity is negligible.
94+
if chromatic_aberration.intensity > 1e-4 {
10295
Some(chromatic_aberration.clone())
10396
} else {
10497
None
@@ -112,13 +105,8 @@ impl ExtractComponent for ChromaticAberration {
112105
/// each of these fields.
113106
#[derive(ShaderType, Default)]
114107
pub struct ChromaticAberrationUniform {
115-
/// The intensity of the effect, in a fraction of the screen.
116108
pub(super) intensity: f32,
117-
/// A cap on the number of samples of the source texture that the shader
118-
/// will perform.
119109
pub(super) max_samples: u32,
120-
/// Padding data.
121110
pub(super) unused_1: u32,
122-
/// Padding data.
123111
pub(super) unused_2: u32,
124112
}

crates/bevy_post_process/src/effect_stack/chromatic_aberration.wgsl

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@ struct ChromaticAberrationSettings {
1616
// The source framebuffer texture.
1717
@group(0) @binding(0) var source_texture: texture_2d<f32>;
1818
// The sampler used to sample the source framebuffer texture.
19-
@group(0) @binding(1) var source_sampler: sampler;
19+
@group(0) @binding(1) var common_sampler: sampler;
2020
// The 1D lookup table for chromatic aberration.
2121
@group(0) @binding(2) var chromatic_aberration_lut_texture: texture_2d<f32>;
22-
// The sampler used to sample that lookup table.
23-
@group(0) @binding(3) var chromatic_aberration_lut_sampler: sampler;
2422
// The settings supplied by the developer.
25-
@group(0) @binding(4) var<uniform> chromatic_aberration_settings: ChromaticAberrationSettings;
23+
@group(0) @binding(3) var<uniform> chromatic_aberration_settings: ChromaticAberrationSettings;
2624

2725
fn chromatic_aberration(start_pos: vec2<f32>) -> vec3<f32> {
2826
// Radial chromatic aberration implemented using the *Inside* technique:
@@ -56,7 +54,7 @@ fn chromatic_aberration(start_pos: vec2<f32>) -> vec3<f32> {
5654
let sample_uv = mix(start_pos, end_pos, t);
5755
let sample = textureSampleLevel(
5856
source_texture,
59-
source_sampler,
57+
common_sampler,
6058
sample_uv,
6159
0.0,
6260
).rgb;
@@ -65,7 +63,7 @@ fn chromatic_aberration(start_pos: vec2<f32>) -> vec3<f32> {
6563
let lut_u = mix(lut_u_offset, 1.0 - lut_u_offset, t);
6664
let modulate = textureSampleLevel(
6765
chromatic_aberration_lut_texture,
68-
chromatic_aberration_lut_sampler,
66+
common_sampler,
6967
vec2(lut_u, 0.5),
7068
0.0,
7169
).rgb;
@@ -82,7 +80,7 @@ fn chromatic_aberration(start_pos: vec2<f32>) -> vec3<f32> {
8280
// texture to such pixels, which is wrong.
8381
color = textureSampleLevel(
8482
source_texture,
85-
source_sampler,
83+
common_sampler,
8684
start_pos,
8785
0.0,
8886
).rgb;

crates/bevy_post_process/src/effect_stack/lens_distortion.wgsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ const VISUAL_THRESHOLD: f32 = 1e-4;
1717
const MATH_EPSILON: f32 = 1e-6;
1818

1919
// The settings supplied by the developer.
20-
@group(0) @binding(6) var<uniform> lens_distortion_settings: LensDistortionSettings;
20+
@group(0) @binding(5) var<uniform> lens_distortion_settings: LensDistortionSettings;
2121

22-
fn lens_distortion(uv: vec2<f32>) -> vec2<f32>{
22+
fn lens_distortion(uv: vec2<f32>) -> vec2<f32> {
2323
let intensity = lens_distortion_settings.intensity;
2424
if (abs(intensity) < VISUAL_THRESHOLD) {
2525
return uv;

crates/bevy_post_process/src/effect_stack/mod.rs

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ mod lens_distortion;
1111
mod vignette;
1212

1313
use bevy_color::ColorToComponents;
14-
use bevy_math::Vec2;
1514
pub use chromatic_aberration::{ChromaticAberration, ChromaticAberrationUniform};
1615
pub use lens_distortion::{LensDistortion, LensDistortionUniform};
1716
pub use vignette::{Vignette, VignetteUniform};
@@ -81,10 +80,8 @@ pub struct EffectStackPlugin;
8180
pub struct PostProcessingPipeline {
8281
/// The layout of bind group 0, containing the source, LUT, and settings.
8382
bind_group_layout: BindGroupLayoutDescriptor,
84-
/// Specifies how to sample the source framebuffer texture.
85-
source_sampler: Sampler,
86-
/// Specifies how to sample the chromatic aberration gradient.
87-
chromatic_aberration_lut_sampler: Sampler,
83+
/// A shared sampler used to sample both the source framebuffer texture and the LUT texture.
84+
common_sampler: Sampler,
8885
/// The asset handle for the fullscreen vertex shader.
8986
fullscreen_shader: FullscreenShader,
9087
/// The fragment shader asset handle.
@@ -176,7 +173,7 @@ impl Plugin for EffectStackPlugin {
176173
}
177174
}
178175

179-
pub fn init_post_processing_pipeline(
176+
pub(crate) fn init_post_processing_pipeline(
180177
mut commands: Commands,
181178
render_device: Res<RenderDevice>,
182179
fullscreen_shader: Res<FullscreenShader>,
@@ -190,12 +187,10 @@ pub fn init_post_processing_pipeline(
190187
(
191188
// Common source:
192189
texture_2d(TextureSampleType::Float { filterable: true }),
193-
// Common source sampler:
190+
// Common sampler:
194191
sampler(SamplerBindingType::Filtering),
195192
// Chromatic aberration LUT:
196193
texture_2d(TextureSampleType::Float { filterable: true }),
197-
// Chromatic aberration LUT sampler:
198-
sampler(SamplerBindingType::Filtering),
199194
// Chromatic aberration settings:
200195
uniform_buffer::<ChromaticAberrationUniform>(true),
201196
// Vignette settings:
@@ -208,15 +203,7 @@ pub fn init_post_processing_pipeline(
208203

209204
// Both source and chromatic aberration LUTs should be sampled
210205
// bilinearly.
211-
212-
let source_sampler = render_device.create_sampler(&SamplerDescriptor {
213-
mipmap_filter: MipmapFilterMode::Linear,
214-
min_filter: FilterMode::Linear,
215-
mag_filter: FilterMode::Linear,
216-
..default()
217-
});
218-
219-
let chromatic_aberration_lut_sampler = render_device.create_sampler(&SamplerDescriptor {
206+
let common_sampler = render_device.create_sampler(&SamplerDescriptor {
220207
mipmap_filter: MipmapFilterMode::Linear,
221208
min_filter: FilterMode::Linear,
222209
mag_filter: FilterMode::Linear,
@@ -225,8 +212,7 @@ pub fn init_post_processing_pipeline(
225212

226213
commands.insert_resource(PostProcessingPipeline {
227214
bind_group_layout,
228-
source_sampler,
229-
chromatic_aberration_lut_sampler,
215+
common_sampler,
230216
fullscreen_shader: fullscreen_shader.clone(),
231217
fragment_shader: load_embedded_asset!(asset_server.as_ref(), "post_process.wgsl"),
232218
});
@@ -335,9 +321,8 @@ pub(crate) fn post_processing(
335321
&pipeline_cache.get_bind_group_layout(&post_processing_pipeline.bind_group_layout),
336322
&BindGroupEntries::sequential((
337323
post_process.source,
338-
&post_processing_pipeline.source_sampler,
324+
&post_processing_pipeline.common_sampler,
339325
&chromatic_aberration_lut.texture_view,
340-
&post_processing_pipeline.chromatic_aberration_lut_sampler,
341326
chromatic_aberration_uniform_buffer_binding,
342327
vignette_uniform_buffer_binding,
343328
lens_distortion_uniform_buffer_binding,
@@ -366,7 +351,7 @@ pub(crate) fn post_processing(
366351
}
367352

368353
/// Specializes the built-in postprocessing pipeline for each applicable view.
369-
pub fn prepare_post_processing_pipelines(
354+
pub(crate) fn prepare_post_processing_pipelines(
370355
mut commands: Commands,
371356
pipeline_cache: Res<PipelineCache>,
372357
mut pipelines: ResMut<SpecializedRenderPipelines<PostProcessingPipeline>>,
@@ -398,7 +383,7 @@ pub fn prepare_post_processing_pipelines(
398383

399384
/// Gathers the built-in postprocessing settings for every view and uploads them
400385
/// to the GPU.
401-
pub fn prepare_post_processing_uniforms(
386+
pub(crate) fn prepare_post_processing_uniforms(
402387
mut commands: Commands,
403388
mut post_processing_uniform_buffers: ResMut<PostProcessingUniformBuffers>,
404389
render_device: Res<RenderDevice>,
@@ -419,6 +404,7 @@ pub fn prepare_post_processing_uniforms(
419404
) {
420405
post_processing_uniform_buffers.chromatic_aberration.clear();
421406
post_processing_uniform_buffers.vignette.clear();
407+
post_processing_uniform_buffers.lens_distortion.clear();
422408

423409
// Gather up all the postprocessing settings.
424410
for (view_entity, maybe_chromatic_aberration, maybe_vignette, maybe_lens_distortion) in
@@ -444,10 +430,10 @@ pub fn prepare_post_processing_uniforms(
444430
post_processing_uniform_buffers
445431
.vignette
446432
.push(&VignetteUniform {
447-
intensity: vignette.intensity,
448-
radius: vignette.radius,
449-
smoothness: vignette.smoothness,
450-
roundness: vignette.roundness,
433+
intensity: vignette.intensity.min(1.0),
434+
radius: vignette.radius.max(1e-6),
435+
smoothness: vignette.smoothness.max(0.0),
436+
roundness: vignette.roundness.clamp(1e-6, 2.0 - 1e-6),
451437
center: vignette.center,
452438
edge_compensation: vignette.edge_compensation,
453439
unused: 0,
@@ -466,8 +452,8 @@ pub fn prepare_post_processing_uniforms(
466452
.push(&LensDistortionUniform {
467453
intensity: lens_distortion.intensity,
468454
scale: lens_distortion.scale.max(1e-6),
469-
multiplier: lens_distortion.multiplier.max(Vec2::ZERO),
470-
center: lens_distortion.center.clamp(Vec2::ZERO, Vec2::ONE),
455+
multiplier: lens_distortion.multiplier,
456+
center: lens_distortion.center,
471457
edge_curvature: lens_distortion.edge_curvature,
472458
unused: 0,
473459
})

crates/bevy_post_process/src/effect_stack/vignette.rs

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,6 @@ use bevy_render::{
1212
extract_component::ExtractComponent, render_resource::ShaderType, sync_component::SyncComponent,
1313
};
1414

15-
/// The default vignette intensity amount.
16-
const DEFAULT_VIGNETTE_INTENSITY: f32 = 1.0;
17-
18-
/// The default vignette radius amount.
19-
const DEFAULT_VIGNETTE_RADIUS: f32 = 0.75;
20-
21-
/// The default vignette smoothness amount.
22-
const DEFAULT_VIGNETTE_SMOOTHNESS: f32 = 5.0;
23-
24-
/// The default vignette roundness amount.
25-
const DEFAULT_VIGNETTE_ROUNDNESS: f32 = 1.0;
26-
27-
/// The default vignette edge compensation
28-
const DEFAULT_VIGNETTE_EDGE_COMPENSATION: f32 = 1.0;
29-
3015
/// Adds a gradual shading effect to the edges of the screen, drawing focus
3116
/// towards the center.
3217
///
@@ -91,12 +76,12 @@ pub struct Vignette {
9176
impl Default for Vignette {
9277
fn default() -> Self {
9378
Self {
94-
intensity: DEFAULT_VIGNETTE_INTENSITY,
95-
radius: DEFAULT_VIGNETTE_RADIUS,
96-
smoothness: DEFAULT_VIGNETTE_SMOOTHNESS,
97-
roundness: DEFAULT_VIGNETTE_ROUNDNESS,
79+
intensity: 1.0,
80+
radius: 0.75,
81+
smoothness: 5.0,
82+
roundness: 1.0,
9883
color: Color::BLACK,
99-
edge_compensation: DEFAULT_VIGNETTE_EDGE_COMPENSATION,
84+
edge_compensation: 1.0,
10085
center: Vec2::new(0.5, 0.5),
10186
}
10287
}
@@ -112,31 +97,27 @@ impl ExtractComponent for Vignette {
11297
type Out = Self;
11398

11499
fn extract_component(vignette: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
115-
// Skip the postprocessing phase entirely if the intensity is zero.
116-
if vignette.intensity > 0.0 {
100+
// Skip the postprocessing phase entirely if the intensity is negligible.
101+
if vignette.intensity > 1e-4 {
117102
Some(vignette.clone())
118103
} else {
119104
None
120105
}
121106
}
122107
}
123108

109+
/// The on-GPU version of the [`Vignette`] settings.
110+
///
111+
/// See the documentation for [`Vignette`] for more information on
112+
/// each of these fields.
124113
#[derive(ShaderType, Default)]
125114
pub struct VignetteUniform {
126-
/// Controls the strength of the darkening effect.
127115
pub(super) intensity: f32,
128-
/// The size of the unvignetted center area.
129116
pub(super) radius: f32,
130-
/// The softness of the edge between the clear and dark areas.
131117
pub(super) smoothness: f32,
132-
/// The shape of the vignette.
133118
pub(super) roundness: f32,
134-
/// The center of the vignette.
135119
pub(super) center: Vec2,
136-
/// The edge compensation of the vignette.
137120
pub(super) edge_compensation: f32,
138-
/// Padding data.
139121
pub(super) unused: u32,
140-
/// The color of the vignette.
141122
pub(super) color: Vec4,
142123
}

crates/bevy_post_process/src/effect_stack/vignette.wgsl

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,20 @@ struct VignetteSettings {
1717
color: vec4<f32>
1818
}
1919

20-
const EPSILON: f32 = 1.19209290e-07;
20+
const VISUAL_THRESHOLD: f32 = 1e-4;
2121

2222
// The settings supplied by the developer.
23-
@group(0) @binding(5) var<uniform> vignette_settings: VignetteSettings;
23+
@group(0) @binding(4) var<uniform> vignette_settings: VignetteSettings;
2424

2525
fn vignette(uv: vec2<f32>, color: vec3<f32>) -> vec3<f32> {
26-
if (vignette_settings.intensity < EPSILON) {
26+
let intensity = vignette_settings.intensity;
27+
if (intensity < VISUAL_THRESHOLD) {
2728
return color;
2829
}
29-
30-
let intensity = saturate(vignette_settings.intensity);
31-
let radius = max(vignette_settings.radius, 0.0);
32-
let smoothness = max(vignette_settings.smoothness, 0.0);
33-
let roundness = clamp(vignette_settings.roundness, EPSILON, 2.0-EPSILON);
34-
let edge_comp = saturate(vignette_settings.edge_compensation);
30+
let radius = vignette_settings.radius;
31+
let smoothness = vignette_settings.smoothness;
32+
let roundness = vignette_settings.roundness;
33+
let edge_comp = vignette_settings.edge_compensation;
3534

3635
// Get the screen resolution.
3736
let dims = textureDimensions(source_texture);

0 commit comments

Comments
 (0)