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