1// The chromatic aberration postprocessing effect.2//3// This makes edges of objects turn into multicolored streaks.5#define_import_path bevy_post_process::effect_stack::chromatic_aberration7// See `bevy_post_process::effect_stack::ChromaticAberration` for more8// information on these fields.9struct ChromaticAberrationSettings {10 intensity: f32,11 max_samples: u32,12 unused_a: u32,13 unused_b: u32,14}16// The source framebuffer texture.17@group(0) @binding(0) var source_texture: texture_2d<f32>;18// The sampler used to sample the source framebuffer texture.19@group(0) @binding(1) var common_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 settings supplied by the developer.23@group(0) @binding(3) var<uniform> chromatic_aberration_settings: ChromaticAberrationSettings;25fn chromatic_aberration(start_pos: vec2<f32>) -> vec3<f32> {26 // Radial chromatic aberration implemented using the *Inside* technique:27 //28 // <https://github.com/playdeadgames/publications/blob/master/INSIDE/rendering_inside_gdc2016.pdf>30 let end_pos = mix(start_pos, vec2(0.5), chromatic_aberration_settings.intensity);32 // Determine the number of samples. We aim for one sample per texel, unless33 // that's higher than the developer-specified maximum number of samples, in34 // which case we choose the maximum number of samples.35 let texel_length = length((end_pos - start_pos) *36 vec2<f32>(textureDimensions(source_texture)));37 let sample_count = min(u32(ceil(texel_length)), chromatic_aberration_settings.max_samples);39 var color: vec3<f32>;40 if (sample_count > 1u) {41 // The LUT texture is in clamp-to-edge mode, so we start at 0.5 texels42 // from the sides so that we have a nice gradient over the entire LUT43 // range.44 let lut_u_offset = 0.5 / f32(textureDimensions(chromatic_aberration_lut_texture).x);46 var sample_sum = vec3(0.0);47 var modulate_sum = vec3(0.0);49 // Start accumulating samples.50 for (var sample_index = 0u; sample_index < sample_count; sample_index += 1u) {51 let t = (f32(sample_index) + 0.5) / f32(sample_count);53 // Sample the framebuffer.54 let sample_uv = mix(start_pos, end_pos, t);55 let sample = textureSampleLevel(56 source_texture,57 common_sampler,58 sample_uv,59 0.0,60 ).rgb;62 // Sample the LUT.63 let lut_u = mix(lut_u_offset, 1.0 - lut_u_offset, t);64 let modulate = textureSampleLevel(65 chromatic_aberration_lut_texture,66 common_sampler,67 vec2(lut_u, 0.5),68 0.0,69 ).rgb;71 // Modulate the sample by the LUT value.72 sample_sum += sample * modulate;73 modulate_sum += modulate;74 }76 color = sample_sum / modulate_sum;77 } else {78 // If there's only one sample, don't do anything. If we don't do this,79 // then this shader will apply whatever tint is in the center of the LUT80 // texture to such pixels, which is wrong.81 color = textureSampleLevel(82 source_texture,83 common_sampler,84 start_pos,85 0.0,86 ).rgb;87 }89 return color;90}