9#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput 11@group(0) @binding(0) var screenTexture: texture_2d<f32>; 12@group(0) @binding(1) var samp: sampler; 15#ifdef EDGE_THRESH_MIN_LOW 16 const EDGE_THRESHOLD_MIN: f32 = 0.0833; 19#ifdef EDGE_THRESH_MIN_MEDIUM 20 const EDGE_THRESHOLD_MIN: f32 = 0.0625; 23#ifdef EDGE_THRESH_MIN_HIGH 24 const EDGE_THRESHOLD_MIN: f32 = 0.0312; 27#ifdef EDGE_THRESH_MIN_ULTRA 28 const EDGE_THRESHOLD_MIN: f32 = 0.0156; 31#ifdef EDGE_THRESH_MIN_EXTREME 32 const EDGE_THRESHOLD_MIN: f32 = 0.0078; 37 const EDGE_THRESHOLD_MAX: f32 = 0.250; 40#ifdef EDGE_THRESH_MEDIUM 41 const EDGE_THRESHOLD_MAX: f32 = 0.166; 44#ifdef EDGE_THRESH_HIGH 45 const EDGE_THRESHOLD_MAX: f32 = 0.125; 48#ifdef EDGE_THRESH_ULTRA 49 const EDGE_THRESHOLD_MAX: f32 = 0.063; 52#ifdef EDGE_THRESH_EXTREME 53 const EDGE_THRESHOLD_MAX: f32 = 0.031; 56const ITERATIONS: i32 = 12; 57const SUBPIXEL_QUALITY: f32 = 0.75; 59fn QUALITY(q: i32) -> f32 { 62 default: { return 1.0; } 63 case 5: { return 1.5; } 64 case 6, 7, 8, 9: { return 2.0; } 65 case 10: { return 4.0; } 66 case 11: { return 8.0; } 70fn rgb2luma(rgb: vec3<f32>) -> f32 { 71 return sqrt(dot(rgb, vec3<f32>(0.299, 0.587, 0.114))); 76fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> { 77 let resolution = vec2<f32>(textureDimensions(screenTexture)); 78 let inverseScreenSize = 1.0 / resolution.xy; 79 let texCoord = in.position.xy * inverseScreenSize; 81 let centerSample = textureSampleLevel(screenTexture, samp, texCoord, 0.0); 82 let colorCenter = centerSample.rgb; 85 let lumaCenter = rgb2luma(colorCenter); 88 let lumaDown = rgb2luma(textureSampleLevel(screenTexture, samp, texCoord, 0.0, vec2<i32>(0, -1)).rgb); 89 let lumaUp = rgb2luma(textureSampleLevel(screenTexture, samp, texCoord, 0.0, vec2<i32>(0, 1)).rgb); 90 let lumaLeft = rgb2luma(textureSampleLevel(screenTexture, samp, texCoord, 0.0, vec2<i32>(-1, 0)).rgb); 91 let lumaRight = rgb2luma(textureSampleLevel(screenTexture, samp, texCoord, 0.0, vec2<i32>(1, 0)).rgb); 94 let lumaMin = min(lumaCenter, min(min(lumaDown, lumaUp), min(lumaLeft, lumaRight))); 95 let lumaMax = max(lumaCenter, max(max(lumaDown, lumaUp), max(lumaLeft, lumaRight))); 98 let lumaRange = lumaMax - lumaMin; 101 if (lumaRange < max(EDGE_THRESHOLD_MIN, lumaMax * EDGE_THRESHOLD_MAX)) { 106 let lumaDownLeft = rgb2luma(textureSampleLevel(screenTexture, samp, texCoord, 0.0, vec2<i32>(-1, -1)).rgb); 107 let lumaUpRight = rgb2luma(textureSampleLevel(screenTexture, samp, texCoord, 0.0, vec2<i32>(1, 1)).rgb); 108 let lumaUpLeft = rgb2luma(textureSampleLevel(screenTexture, samp, texCoord, 0.0, vec2<i32>(-1, 1)).rgb); 109 let lumaDownRight = rgb2luma(textureSampleLevel(screenTexture, samp, texCoord, 0.0, vec2<i32>(1, -1)).rgb); 112 let lumaDownUp = lumaDown + lumaUp; 113 let lumaLeftRight = lumaLeft + lumaRight; 116 let lumaLeftCorners = lumaDownLeft + lumaUpLeft; 117 let lumaDownCorners = lumaDownLeft + lumaDownRight; 118 let lumaRightCorners = lumaDownRight + lumaUpRight; 119 let lumaUpCorners = lumaUpRight + lumaUpLeft; 122 let edgeHorizontal = abs(-2.0 * lumaLeft + lumaLeftCorners) + 123 abs(-2.0 * lumaCenter + lumaDownUp) * 2.0 + 124 abs(-2.0 * lumaRight + lumaRightCorners); 126 let edgeVertical = abs(-2.0 * lumaUp + lumaUpCorners) + 127 abs(-2.0 * lumaCenter + lumaLeftRight) * 2.0 + 128 abs(-2.0 * lumaDown + lumaDownCorners); 131 let isHorizontal = (edgeHorizontal >= edgeVertical); 134 var stepLength = select(inverseScreenSize.x, inverseScreenSize.y, isHorizontal); 137 var luma1 = select(lumaLeft, lumaDown, isHorizontal); 138 var luma2 = select(lumaRight, lumaUp, isHorizontal); 141 let gradient1 = luma1 - lumaCenter; 142 let gradient2 = luma2 - lumaCenter; 145 let is1Steepest = abs(gradient1) >= abs(gradient2); 148 let gradientScaled = 0.25 * max(abs(gradient1), abs(gradient2)); 151 var lumaLocalAverage = 0.0; 154 stepLength = -stepLength; 155 lumaLocalAverage = 0.5 * (luma1 + lumaCenter); 157 lumaLocalAverage = 0.5 * (luma2 + lumaCenter); 162 var currentUv = texCoord; 163 var offset = vec2<f32>(0.0, 0.0); 165 currentUv.y = currentUv.y + stepLength * 0.5; 166 offset.x = inverseScreenSize.x; 168 currentUv.x = currentUv.x + stepLength * 0.5; 169 offset.y = inverseScreenSize.y; 173 var uv1 = currentUv - offset; 174 var uv2 = currentUv + offset; 177 var lumaEnd1 = rgb2luma(textureSampleLevel(screenTexture, samp, uv1, 0.0).rgb); 178 var lumaEnd2 = rgb2luma(textureSampleLevel(screenTexture, samp, uv2, 0.0).rgb); 179 lumaEnd1 = lumaEnd1 - lumaLocalAverage; 180 lumaEnd2 = lumaEnd2 - lumaLocalAverage; 183 var reached1 = abs(lumaEnd1) >= gradientScaled; 184 var reached2 = abs(lumaEnd2) >= gradientScaled; 185 var reachedBoth = reached1 && reached2; 188 uv1 = select(uv1 - offset, uv1, reached1); 189 uv2 = select(uv2 - offset, uv2, reached2); 193 for (var i: i32 = 2; i < ITERATIONS; i = i + 1) { 196 lumaEnd1 = rgb2luma(textureSampleLevel(screenTexture, samp, uv1, 0.0).rgb); 197 lumaEnd1 = lumaEnd1 - lumaLocalAverage; 201 lumaEnd2 = rgb2luma(textureSampleLevel(screenTexture, samp, uv2, 0.0).rgb); 202 lumaEnd2 = lumaEnd2 - lumaLocalAverage; 205 reached1 = abs(lumaEnd1) >= gradientScaled; 206 reached2 = abs(lumaEnd2) >= gradientScaled; 207 reachedBoth = reached1 && reached2; 211 uv1 = uv1 - offset * QUALITY(i); 214 uv2 = uv2 + offset * QUALITY(i); 225 var distance1 = select(texCoord.y - uv1.y, texCoord.x - uv1.x, isHorizontal); 226 var distance2 = select(uv2.y - texCoord.y, uv2.x - texCoord.x, isHorizontal); 229 let isDirection1 = distance1 < distance2; 230 let distanceFinal = min(distance1, distance2); 233 let edgeThickness = (distance1 + distance2); 236 let isLumaCenterSmaller = lumaCenter < lumaLocalAverage; 239 let correctVariation1 = (lumaEnd1 < 0.0) != isLumaCenterSmaller; 240 let correctVariation2 = (lumaEnd2 < 0.0) != isLumaCenterSmaller; 243 var correctVariation = select(correctVariation2, correctVariation1, isDirection1); 246 let pixelOffset = - distanceFinal / edgeThickness + 0.5; 249 var finalOffset = select(0.0, pixelOffset, correctVariation); 253 let lumaAverage = (1.0 / 12.0) * (2.0 * (lumaDownUp + lumaLeftRight) + lumaLeftCorners + lumaRightCorners); 255 let subPixelOffset1 = clamp(abs(lumaAverage - lumaCenter) / lumaRange, 0.0, 1.0); 256 let subPixelOffset2 = (-2.0 * subPixelOffset1 + 3.0) * subPixelOffset1 * subPixelOffset1; 258 let subPixelOffsetFinal = subPixelOffset2 * subPixelOffset2 * SUBPIXEL_QUALITY; 261 finalOffset = max(finalOffset, subPixelOffsetFinal); 264 var finalUv = texCoord; 266 finalUv.y = finalUv.y + finalOffset * stepLength; 268 finalUv.x = finalUv.x + finalOffset * stepLength; 272 var finalColor = textureSampleLevel(screenTexture, samp, finalUv, 0.0).rgb; 273 return vec4<f32>(finalColor, centerSample.a);