Skip to content

Commit fcda67e

Browse files
authored
Start a built-in postprocessing stack, and implement chromatic aberration in it. (#13695)
This commit creates a new built-in postprocessing shader that's designed to hold miscellaneous postprocessing effects, and starts it off with chromatic aberration. Possible future effects include vignette, film grain, and lens distortion. [Chromatic aberration] is a common postprocessing effect that simulates lenses that fail to focus all colors of light to a single point. It's often used for impact effects and/or horror games. This patch uses the technique from *Inside* ([Gjøl & Svendsen 2016]), which allows the developer to customize the particular color pattern to achieve different effects. Unity HDRP uses the same technique, while Unreal has a hard-wired fixed color pattern. A new example, `post_processing`, has been added, in order to demonstrate the technique. The existing `post_processing` shader has been renamed to `custom_post_processing`, for clarity. [Chromatic aberration]: https://en.wikipedia.org/wiki/Chromatic_aberration [Gjøl & Svendsen 2016]: https://github.com/playdeadgames/publications/blob/master/INSIDE/rendering_inside_gdc2016.pdf ![Screenshot 2024-06-04 180304](https://github.com/bevyengine/bevy/assets/157897/3631c64f-a615-44fe-91ca-7f04df0a54b2) ![Screenshot 2024-06-04 180743](https://github.com/bevyengine/bevy/assets/157897/ee055cbf-4314-49c5-8bfa-8d8a17bd52bb) ## Changelog ### Added * Chromatic aberration is now available as a built-in postprocessing effect. To use it, add `ChromaticAberration` to your camera.
1 parent ed2b8e0 commit fcda67e

File tree

10 files changed

+843
-4
lines changed

10 files changed

+843
-4
lines changed

Cargo.toml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,11 +2237,11 @@ category = "Shaders"
22372237
wasm = true
22382238

22392239
[[example]]
2240-
name = "post_processing"
2241-
path = "examples/shader/post_processing.rs"
2240+
name = "custom_post_processing"
2241+
path = "examples/shader/custom_post_processing.rs"
22422242
doc-scrape-examples = true
22432243

2244-
[package.metadata.example.post_processing]
2244+
[package.metadata.example.custom_post_processing]
22452245
name = "Post Processing - Custom Render Pass"
22462246
description = "A custom post processing effect, using a custom render pass that runs after the main pass"
22472247
category = "Shaders"
@@ -3284,6 +3284,17 @@ description = "Handles input, physics, and rendering in an industry-standard way
32843284
category = "Movement"
32853285
wasm = true
32863286

3287+
[[example]]
3288+
name = "post_processing"
3289+
path = "examples/3d/post_processing.rs"
3290+
doc-scrape-examples = true
3291+
3292+
[package.metadata.example.post_processing]
3293+
name = "Built-in postprocessing"
3294+
description = "Demonstrates the built-in postprocessing features"
3295+
category = "3D Rendering"
3296+
wasm = true
3297+
32873298
[profile.wasm-release]
32883299
inherits = "release"
32893300
opt-level = "z"

crates/bevy_core_pipeline/src/core_2d/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub mod graph {
1818
MainTransparentPass,
1919
EndMainPass,
2020
Bloom,
21+
PostProcessing,
2122
Tonemapping,
2223
Fxaa,
2324
Smaa,

crates/bevy_core_pipeline/src/core_3d/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub mod graph {
3030
Bloom,
3131
AutoExposure,
3232
DepthOfField,
33+
PostProcessing,
3334
Tonemapping,
3435
Fxaa,
3536
Smaa,

crates/bevy_core_pipeline/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub mod fullscreen_vertex_shader;
1919
pub mod fxaa;
2020
pub mod motion_blur;
2121
pub mod msaa_writeback;
22+
pub mod post_process;
2223
pub mod prepass;
2324
mod skybox;
2425
pub mod smaa;
@@ -60,6 +61,7 @@ use crate::{
6061
fxaa::FxaaPlugin,
6162
motion_blur::MotionBlurPlugin,
6263
msaa_writeback::MsaaWritebackPlugin,
64+
post_process::PostProcessingPlugin,
6365
prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass},
6466
smaa::SmaaPlugin,
6567
tonemapping::TonemappingPlugin,
@@ -99,6 +101,7 @@ impl Plugin for CorePipelinePlugin {
99101
MotionBlurPlugin,
100102
DepthOfFieldPlugin,
101103
SmaaPlugin,
104+
PostProcessingPlugin,
102105
));
103106
}
104107
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// The chromatic aberration postprocessing effect.
2+
//
3+
// This makes edges of objects turn into multicolored streaks.
4+
5+
#define_import_path bevy_core_pipeline::post_processing::chromatic_aberration
6+
7+
// See `bevy_core_pipeline::post_process::ChromaticAberration` for more
8+
// information on these fields.
9+
struct ChromaticAberrationSettings {
10+
intensity: f32,
11+
max_samples: u32,
12+
unused_a: u32,
13+
unused_b: u32,
14+
}
15+
16+
// The source framebuffer texture.
17+
@group(0) @binding(0) var chromatic_aberration_source_texture: texture_2d<f32>;
18+
// The sampler used to sample the source framebuffer texture.
19+
@group(0) @binding(1) var chromatic_aberration_source_sampler: sampler;
20+
// The 1D lookup table for chromatic aberration.
21+
@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;
24+
// The settings supplied by the developer.
25+
@group(0) @binding(4) var<uniform> chromatic_aberration_settings: ChromaticAberrationSettings;
26+
27+
fn chromatic_aberration(start_pos: vec2<f32>) -> vec3<f32> {
28+
// Radial chromatic aberration implemented using the *Inside* technique:
29+
//
30+
// <https://github.com/playdeadgames/publications/blob/master/INSIDE/rendering_inside_gdc2016.pdf>
31+
32+
let end_pos = mix(start_pos, vec2(0.5), chromatic_aberration_settings.intensity);
33+
34+
// Determine the number of samples. We aim for one sample per texel, unless
35+
// that's higher than the developer-specified maximum number of samples, in
36+
// which case we choose the maximum number of samples.
37+
let texel_length = length((end_pos - start_pos) *
38+
vec2<f32>(textureDimensions(chromatic_aberration_source_texture)));
39+
let sample_count = min(u32(ceil(texel_length)), chromatic_aberration_settings.max_samples);
40+
41+
var color: vec3<f32>;
42+
if (sample_count > 1u) {
43+
// The LUT texture is in clamp-to-edge mode, so we start at 0.5 texels
44+
// from the sides so that we have a nice gradient over the entire LUT
45+
// range.
46+
let lut_u_offset = 0.5 / f32(textureDimensions(chromatic_aberration_lut_texture).x);
47+
48+
var sample_sum = vec3(0.0);
49+
var modulate_sum = vec3(0.0);
50+
51+
// Start accumulating samples.
52+
for (var sample_index = 0u; sample_index < sample_count; sample_index += 1u) {
53+
let t = (f32(sample_index) + 0.5) / f32(sample_count);
54+
55+
// Sample the framebuffer.
56+
let sample_uv = mix(start_pos, end_pos, t);
57+
let sample = textureSampleLevel(
58+
chromatic_aberration_source_texture,
59+
chromatic_aberration_source_sampler,
60+
sample_uv,
61+
0.0,
62+
).rgb;
63+
64+
// Sample the LUT.
65+
let lut_u = mix(lut_u_offset, 1.0 - lut_u_offset, t);
66+
let modulate = textureSampleLevel(
67+
chromatic_aberration_lut_texture,
68+
chromatic_aberration_lut_sampler,
69+
vec2(lut_u, 0.5),
70+
0.0,
71+
).rgb;
72+
73+
// Modulate the sample by the LUT value.
74+
sample_sum += sample * modulate;
75+
modulate_sum += modulate;
76+
}
77+
78+
color = sample_sum / modulate_sum;
79+
} else {
80+
// If there's only one sample, don't do anything. If we don't do this,
81+
// then this shader will apply whatever tint is in the center of the LUT
82+
// texture to such pixels, which is wrong.
83+
color = textureSampleLevel(
84+
chromatic_aberration_source_texture,
85+
chromatic_aberration_source_sampler,
86+
start_pos,
87+
0.0,
88+
).rgb;
89+
}
90+
91+
return color;
92+
}

0 commit comments

Comments
 (0)