// This shader computes the chromatic aberration effect // Since post processing is a fullscreen effect, we use the fullscreen vertex shader provided by bevy. // This will import a vertex shader that renders a single fullscreen triangle. // // A fullscreen triangle is a single triangle that covers the entire screen. // The box in the top left in that diagram is the screen. The 4 x are the corner of the screen // // Y axis // 1 | x-----x...... // 0 | | s | . ´ // -1 | x_____x´ // -2 | : .´ // -3 | :´ // +--------------- X axis // -1 0 1 2 3 // // As you can see, the triangle ends up bigger than the screen. // // You don't need to worry about this too much since bevy will compute the correct UVs for you. #import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput @group(0) @binding(0) var screen_texture: texture_2d<f32>; @group(0) @binding(1) var texture_sampler: sampler; struct ChromaticAberrationSettings { intensity: f32, red_offset: vec2<f32>, green_offset: vec2<f32>, blue_offset: vec2<f32>, #ifdef SIXTEEN_BYTE_ALIGNMENT // WebGL2 structs must be 16 byte aligned. _webgl2_padding: f32 #endif } @group(0) @binding(2) var<uniform> settings: ChromaticAberrationSettings; fn oob(inp: vec2<f32>) -> bool { return inp.x < 0.0 || inp.x > 1.0 || inp.y < 0.0 || inp.y > 1.0; } @fragment fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> { // Chromatic aberration strength // screen center is at (0.5, 0.5)uv, so multiply strength by magnitude of uv to get 0 at center // full at edges let offset_strength = settings.intensity * length(in.uv - vec2(0.5, 0.5)) * 2.0; let red_source = in.uv + normalize(settings.red_offset) * offset_strength; let green_source = in.uv + normalize(settings.green_offset) * offset_strength; let blue_source = in.uv + normalize(settings.blue_offset) * offset_strength; var red_pixel = textureSample(screen_texture, texture_sampler, red_source); var green_pixel = textureSample(screen_texture, texture_sampler, green_source); var blue_pixel = textureSample(screen_texture, texture_sampler, blue_source); if (oob(red_source)) { red_pixel = vec4<f32>(0.0); } if (oob(green_source)) { green_pixel = vec4<f32>(0.0); } if (oob(blue_source)) { blue_pixel = vec4<f32>(0.0); } // Sample each color channel with an arbitrary shift return vec4<f32>( red_pixel.r, green_pixel.g, blue_pixel.b, 1.0 ); }