1// The chromatic aberration postprocessing effect.2//3// This makes edges of objects turn into multicolored streaks.5#define_import_path bevy_core_pipeline::post_processing::chromatic_aberration7// See `bevy_core_pipeline::post_process::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 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;27fn 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>32 let end_pos = mix(start_pos, vec2(0.5), chromatic_aberration_settings.intensity);34 // Determine the number of samples. We aim for one sample per texel, unless35 // that's higher than the developer-specified maximum number of samples, in36 // 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);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 texels44 // from the sides so that we have a nice gradient over the entire LUT45 // range.46 let lut_u_offset = 0.5 / f32(textureDimensions(chromatic_aberration_lut_texture).x);48 var sample_sum = vec3(0.0);49 var modulate_sum = vec3(0.0);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);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;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;73 // Modulate the sample by the LUT value.74 sample_sum += sample * modulate;75 modulate_sum += modulate;76 }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 LUT82 // 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 }91 return color;92}