diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 380090935ee..288b12030fc 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -145,15 +145,21 @@ Copyright: 2001, Robert Penner 2007-2014, Juan Linietsky, Ariel Manzur License: Expat -Files: servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl - servers/rendering/renderer_rd/shaders/ssao_blur.glsl - servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl - servers/rendering/renderer_rd/shaders/ssao_interleave.glsl - servers/rendering/renderer_rd/shaders/ssao.glsl - servers/rendering/renderer_rd/shaders/ssil_blur.glsl - servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl - servers/rendering/renderer_rd/shaders/ssil_interleave.glsl - servers/rendering/renderer_rd/shaders/ssil.glsl +Files: ./servers/rendering/renderer_rd/shaders/effects/tonemap.glsl +Comment: NVidia's FXAA 3.11, simplified by Simon Rodriguez +Copyright: 2014-2015, NVIDIA CORPORATION + 2017 Simon Rodriguez +License: BSD-3-clause and Expat + +Files: ./servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl + ./servers/rendering/renderer_rd/shaders/ssao_blur.glsl + ./servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl + ./servers/rendering/renderer_rd/shaders/ssao_interleave.glsl + ./servers/rendering/renderer_rd/shaders/ssao.glsl + ./servers/rendering/renderer_rd/shaders/ssil_blur.glsl + ./servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl + ./servers/rendering/renderer_rd/shaders/ssil_interleave.glsl + ./servers/rendering/renderer_rd/shaders/ssil.glsl Comment: Intel ASSAO and related files Copyright: 2016, Intel Corporation License: Expat diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl index 3bb26d29d15..1b3addf0d49 100644 --- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl @@ -452,60 +452,374 @@ vec3 apply_color_correction(vec3 color) { #endif #ifndef SUBPASS + +// FXAA 3.11 compact, Ported from https://github.com/kosua20/Rendu/blob/master/resources/common/shaders/screens/fxaa.frag +/////////////////////////////////////////////////////////////////////////////////// +// MIT License +// +// Copyright (c) 2017 Simon Rodriguez +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +/////////////////////////////////////////////////////////////////////////////////// + +// Nvidia Original FXAA 3.11 License +//---------------------------------------------------------------------------------- +// File: es3-kepler\FXAA/FXAA3_11.h +// SDK Version: v3.00 +// Email: gameworks@nvidia.com +// Site: http://developer.nvidia.com/ +// +// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +//---------------------------------------------------------------------------------- +// +// NVIDIA FXAA 3.11 by TIMOTHY LOTTES +// +//---------------------------------------------------------------------------------- + +float QUALITY(float q) { + return (q < 5 ? 1.0 : (q > 5 ? (q < 10 ? 2.0 : (q < 11 ? 4.0 : 8.0)) : 1.5)); +} + +float rgb2luma(vec3 rgb) { + return sqrt(dot(rgb, vec3(0.299, 0.587, 0.114))); +} + vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { - const float FXAA_REDUCE_MIN = (1.0 / 128.0); - const float FXAA_REDUCE_MUL = (1.0 / 8.0); - const float FXAA_SPAN_MAX = 8.0; + const float EDGE_THRESHOLD_MIN = 0.0312; + const float EDGE_THRESHOLD_MAX = 0.125; + const int ITERATIONS = 12; + const float SUBPIXEL_QUALITY = 0.75; #ifdef USE_MULTIVIEW - vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-0.5, -0.5) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(0.5, -0.5) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-0.5, 0.5) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbSE = textureLod(source_color, vec3(uv_interp + vec2(0.5, 0.5) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; -#else - vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-0.5, -0.5) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbNE = textureLod(source_color, uv_interp + vec2(0.5, -0.5) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-0.5, 0.5) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; - vec3 rgbSE = textureLod(source_color, uv_interp + vec2(0.5, 0.5) * params.pixel_size, 0.0).xyz * exposure * params.luminance_multiplier; -#endif - vec3 rgbM = color; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + float lumaUp = rgb2luma(textureLodOffset(source_color, vec3(uv_interp, ViewIndex), 0.0, ivec2(0, 1)).xyz * exposure * params.luminance_multiplier); + float lumaDown = rgb2luma(textureLodOffset(source_color, vec3(uv_interp, ViewIndex), 0.0, ivec2(0, -1)).xyz * exposure * params.luminance_multiplier); + float lumaLeft = rgb2luma(textureLodOffset(source_color, vec3(uv_interp, ViewIndex), 0.0, ivec2(-1, 0)).xyz * exposure * params.luminance_multiplier); + float lumaRight = rgb2luma(textureLodOffset(source_color, vec3(uv_interp, ViewIndex), 0.0, ivec2(1, 0)).xyz * exposure * params.luminance_multiplier); - vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + float lumaCenter = rgb2luma(color); - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), - FXAA_REDUCE_MIN); + float lumaMin = min(lumaCenter, min(min(lumaUp, lumaDown), min(lumaLeft, lumaRight))); + float lumaMax = max(lumaCenter, max(max(lumaUp, lumaDown), max(lumaLeft, lumaRight))); - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * - params.pixel_size; + float lumaRange = lumaMax - lumaMin; -#ifdef USE_MULTIVIEW - vec3 rgbA = 0.5 * exposure * (textureLod(source_color, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz) * params.luminance_multiplier; - vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz) * params.luminance_multiplier; -#else - vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz) * params.luminance_multiplier; - vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz) * params.luminance_multiplier; -#endif - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) { - return rgbA; - } else { - return rgbB; + if (lumaRange < max(EDGE_THRESHOLD_MIN, lumaMax * EDGE_THRESHOLD_MAX)) { + return color; } + + float lumaDownLeft = rgb2luma(textureLodOffset(source_color, vec3(uv_interp, ViewIndex), 0.0, ivec2(-1, -1)).xyz * exposure * params.luminance_multiplier); + float lumaUpRight = rgb2luma(textureLodOffset(source_color, vec3(uv_interp, ViewIndex), 0.0, ivec2(1, 1)).xyz * exposure * params.luminance_multiplier); + float lumaUpLeft = rgb2luma(textureLodOffset(source_color, vec3(uv_interp, ViewIndex), 0.0, ivec2(-1, 1)).xyz * exposure * params.luminance_multiplier); + float lumaDownRight = rgb2luma(textureLodOffset(source_color, vec3(uv_interp, ViewIndex), 0.0, ivec2(1, -1)).xyz * exposure * params.luminance_multiplier); + + float lumaDownUp = lumaDown + lumaUp; + float lumaLeftRight = lumaLeft + lumaRight; + + float lumaLeftCorners = lumaDownLeft + lumaUpLeft; + float lumaDownCorners = lumaDownLeft + lumaDownRight; + float lumaRightCorners = lumaDownRight + lumaUpRight; + float lumaUpCorners = lumaUpRight + lumaUpLeft; + + float edgeHorizontal = abs(-2.0 * lumaLeft + lumaLeftCorners) + abs(-2.0 * lumaCenter + lumaDownUp) * 2.0 + abs(-2.0 * lumaRight + lumaRightCorners); + float edgeVertical = abs(-2.0 * lumaUp + lumaUpCorners) + abs(-2.0 * lumaCenter + lumaLeftRight) * 2.0 + abs(-2.0 * lumaDown + lumaDownCorners); + + bool isHorizontal = (edgeHorizontal >= edgeVertical); + + float stepLength = isHorizontal ? params.pixel_size.y : params.pixel_size.x; + + float luma1 = isHorizontal ? lumaDown : lumaLeft; + float luma2 = isHorizontal ? lumaUp : lumaRight; + float gradient1 = luma1 - lumaCenter; + float gradient2 = luma2 - lumaCenter; + + bool is1Steepest = abs(gradient1) >= abs(gradient2); + + float gradientScaled = 0.25 * max(abs(gradient1), abs(gradient2)); + + float lumaLocalAverage = 0.0; + if (is1Steepest) { + stepLength = -stepLength; + lumaLocalAverage = 0.5 * (luma1 + lumaCenter); + } else { + lumaLocalAverage = 0.5 * (luma2 + lumaCenter); + } + + vec2 currentUv = uv_interp; + if (isHorizontal) { + currentUv.y += stepLength * 0.5; + } else { + currentUv.x += stepLength * 0.5; + } + + vec2 offset = isHorizontal ? vec2(params.pixel_size.x, 0.0) : vec2(0.0, params.pixel_size.y); + vec3 uv1 = vec3(currentUv - offset * QUALITY(0), ViewIndex); + vec3 uv2 = vec3(currentUv + offset * QUALITY(0), ViewIndex); + + float lumaEnd1 = rgb2luma(textureLod(source_color, uv1, 0.0).xyz * exposure * params.luminance_multiplier); + float lumaEnd2 = rgb2luma(textureLod(source_color, uv2, 0.0).xyz * exposure * params.luminance_multiplier); + lumaEnd1 -= lumaLocalAverage; + lumaEnd2 -= lumaLocalAverage; + + bool reached1 = abs(lumaEnd1) >= gradientScaled; + bool reached2 = abs(lumaEnd2) >= gradientScaled; + bool reachedBoth = reached1 && reached2; + + if (!reached1) { + uv1 -= vec3(offset * QUALITY(1), 0.0); + } + if (!reached2) { + uv2 += vec3(offset * QUALITY(1), 0.0); + } + + if (!reachedBoth) { + for (int i = 2; i < ITERATIONS; i++) { + if (!reached1) { + lumaEnd1 = rgb2luma(textureLod(source_color, uv1, 0.0).xyz * exposure * params.luminance_multiplier); + lumaEnd1 = lumaEnd1 - lumaLocalAverage; + } + if (!reached2) { + lumaEnd2 = rgb2luma(textureLod(source_color, uv2, 0.0).xyz * exposure * params.luminance_multiplier); + lumaEnd2 = lumaEnd2 - lumaLocalAverage; + } + reached1 = abs(lumaEnd1) >= gradientScaled; + reached2 = abs(lumaEnd2) >= gradientScaled; + reachedBoth = reached1 && reached2; + if (!reached1) { + uv1 -= vec3(offset * QUALITY(i), 0.0); + } + if (!reached2) { + uv2 += vec3(offset * QUALITY(i), 0.0); + } + if (reachedBoth) { + break; + } + } + } + + float distance1 = isHorizontal ? (uv_interp.x - uv1.x) : (uv_interp.y - uv1.y); + float distance2 = isHorizontal ? (uv2.x - uv_interp.x) : (uv2.y - uv_interp.y); + + bool isDirection1 = distance1 < distance2; + float distanceFinal = min(distance1, distance2); + + float edgeThickness = (distance1 + distance2); + + bool isLumaCenterSmaller = lumaCenter < lumaLocalAverage; + + bool correctVariation1 = (lumaEnd1 < 0.0) != isLumaCenterSmaller; + bool correctVariation2 = (lumaEnd2 < 0.0) != isLumaCenterSmaller; + + bool correctVariation = isDirection1 ? correctVariation1 : correctVariation2; + + float pixelOffset = -distanceFinal / edgeThickness + 0.5; + + float finalOffset = correctVariation ? pixelOffset : 0.0; + + float lumaAverage = (1.0 / 12.0) * (2.0 * (lumaDownUp + lumaLeftRight) + lumaLeftCorners + lumaRightCorners); + + float subPixelOffset1 = clamp(abs(lumaAverage - lumaCenter) / lumaRange, 0.0, 1.0); + float subPixelOffset2 = (-2.0 * subPixelOffset1 + 3.0) * subPixelOffset1 * subPixelOffset1; + + float subPixelOffsetFinal = subPixelOffset2 * subPixelOffset2 * SUBPIXEL_QUALITY; + + finalOffset = max(finalOffset, subPixelOffsetFinal); + + vec3 finalUv = vec3(uv_interp, ViewIndex); + if (isHorizontal) { + finalUv.y += finalOffset * stepLength; + } else { + finalUv.x += finalOffset * stepLength; + } + + vec3 finalColor = textureLod(source_color, finalUv, 0.0).xyz * exposure * params.luminance_multiplier; + return finalColor; + +#else + float lumaUp = rgb2luma(textureLodOffset(source_color, uv_interp, 0.0, ivec2(0, 1)).xyz * exposure * params.luminance_multiplier); + float lumaDown = rgb2luma(textureLodOffset(source_color, uv_interp, 0.0, ivec2(0, -1)).xyz * exposure * params.luminance_multiplier); + float lumaLeft = rgb2luma(textureLodOffset(source_color, uv_interp, 0.0, ivec2(-1, 0)).xyz * exposure * params.luminance_multiplier); + float lumaRight = rgb2luma(textureLodOffset(source_color, uv_interp, 0.0, ivec2(1, 0)).xyz * exposure * params.luminance_multiplier); + + float lumaCenter = rgb2luma(color); + + float lumaMin = min(lumaCenter, min(min(lumaUp, lumaDown), min(lumaLeft, lumaRight))); + float lumaMax = max(lumaCenter, max(max(lumaUp, lumaDown), max(lumaLeft, lumaRight))); + + float lumaRange = lumaMax - lumaMin; + + if (lumaRange < max(EDGE_THRESHOLD_MIN, lumaMax * EDGE_THRESHOLD_MAX)) { + return color; + } + + float lumaDownLeft = rgb2luma(textureLodOffset(source_color, uv_interp, 0.0, ivec2(-1, -1)).xyz * exposure * params.luminance_multiplier); + float lumaUpRight = rgb2luma(textureLodOffset(source_color, uv_interp, 0.0, ivec2(1, 1)).xyz * exposure * params.luminance_multiplier); + float lumaUpLeft = rgb2luma(textureLodOffset(source_color, uv_interp, 0.0, ivec2(-1, 1)).xyz * exposure * params.luminance_multiplier); + float lumaDownRight = rgb2luma(textureLodOffset(source_color, uv_interp, 0.0, ivec2(1, -1)).xyz * exposure * params.luminance_multiplier); + + float lumaDownUp = lumaDown + lumaUp; + float lumaLeftRight = lumaLeft + lumaRight; + + float lumaLeftCorners = lumaDownLeft + lumaUpLeft; + float lumaDownCorners = lumaDownLeft + lumaDownRight; + float lumaRightCorners = lumaDownRight + lumaUpRight; + float lumaUpCorners = lumaUpRight + lumaUpLeft; + + float edgeHorizontal = abs(-2.0 * lumaLeft + lumaLeftCorners) + abs(-2.0 * lumaCenter + lumaDownUp) * 2.0 + abs(-2.0 * lumaRight + lumaRightCorners); + float edgeVertical = abs(-2.0 * lumaUp + lumaUpCorners) + abs(-2.0 * lumaCenter + lumaLeftRight) * 2.0 + abs(-2.0 * lumaDown + lumaDownCorners); + + bool isHorizontal = (edgeHorizontal >= edgeVertical); + + float stepLength = isHorizontal ? params.pixel_size.y : params.pixel_size.x; + + float luma1 = isHorizontal ? lumaDown : lumaLeft; + float luma2 = isHorizontal ? lumaUp : lumaRight; + float gradient1 = luma1 - lumaCenter; + float gradient2 = luma2 - lumaCenter; + + bool is1Steepest = abs(gradient1) >= abs(gradient2); + + float gradientScaled = 0.25 * max(abs(gradient1), abs(gradient2)); + + float lumaLocalAverage = 0.0; + if (is1Steepest) { + stepLength = -stepLength; + lumaLocalAverage = 0.5 * (luma1 + lumaCenter); + } else { + lumaLocalAverage = 0.5 * (luma2 + lumaCenter); + } + + vec2 currentUv = uv_interp; + if (isHorizontal) { + currentUv.y += stepLength * 0.5; + } else { + currentUv.x += stepLength * 0.5; + } + + vec2 offset = isHorizontal ? vec2(params.pixel_size.x, 0.0) : vec2(0.0, params.pixel_size.y); + vec2 uv1 = currentUv - offset * QUALITY(0); + vec2 uv2 = currentUv + offset * QUALITY(0); + + float lumaEnd1 = rgb2luma(textureLod(source_color, uv1, 0.0).xyz * exposure * params.luminance_multiplier); + float lumaEnd2 = rgb2luma(textureLod(source_color, uv2, 0.0).xyz * exposure * params.luminance_multiplier); + lumaEnd1 -= lumaLocalAverage; + lumaEnd2 -= lumaLocalAverage; + + bool reached1 = abs(lumaEnd1) >= gradientScaled; + bool reached2 = abs(lumaEnd2) >= gradientScaled; + bool reachedBoth = reached1 && reached2; + + if (!reached1) { + uv1 -= offset * QUALITY(1); + } + if (!reached2) { + uv2 += offset * QUALITY(1); + } + + if (!reachedBoth) { + for (int i = 2; i < ITERATIONS; i++) { + if (!reached1) { + lumaEnd1 = rgb2luma(textureLod(source_color, uv1, 0.0).xyz * exposure * params.luminance_multiplier); + lumaEnd1 = lumaEnd1 - lumaLocalAverage; + } + if (!reached2) { + lumaEnd2 = rgb2luma(textureLod(source_color, uv2, 0.0).xyz * exposure * params.luminance_multiplier); + lumaEnd2 = lumaEnd2 - lumaLocalAverage; + } + reached1 = abs(lumaEnd1) >= gradientScaled; + reached2 = abs(lumaEnd2) >= gradientScaled; + reachedBoth = reached1 && reached2; + if (!reached1) { + uv1 -= offset * QUALITY(i); + } + if (!reached2) { + uv2 += offset * QUALITY(i); + } + if (reachedBoth) { + break; + } + } + } + + float distance1 = isHorizontal ? (uv_interp.x - uv1.x) : (uv_interp.y - uv1.y); + float distance2 = isHorizontal ? (uv2.x - uv_interp.x) : (uv2.y - uv_interp.y); + + bool isDirection1 = distance1 < distance2; + float distanceFinal = min(distance1, distance2); + + float edgeThickness = (distance1 + distance2); + + bool isLumaCenterSmaller = lumaCenter < lumaLocalAverage; + + bool correctVariation1 = (lumaEnd1 < 0.0) != isLumaCenterSmaller; + bool correctVariation2 = (lumaEnd2 < 0.0) != isLumaCenterSmaller; + + bool correctVariation = isDirection1 ? correctVariation1 : correctVariation2; + + float pixelOffset = -distanceFinal / edgeThickness + 0.5; + + float finalOffset = correctVariation ? pixelOffset : 0.0; + + float lumaAverage = (1.0 / 12.0) * (2.0 * (lumaDownUp + lumaLeftRight) + lumaLeftCorners + lumaRightCorners); + + float subPixelOffset1 = clamp(abs(lumaAverage - lumaCenter) / lumaRange, 0.0, 1.0); + float subPixelOffset2 = (-2.0 * subPixelOffset1 + 3.0) * subPixelOffset1 * subPixelOffset1; + + float subPixelOffsetFinal = subPixelOffset2 * subPixelOffset2 * SUBPIXEL_QUALITY; + + finalOffset = max(finalOffset, subPixelOffsetFinal); + + vec2 finalUv = uv_interp; + if (isHorizontal) { + finalUv.y += finalOffset * stepLength; + } else { + finalUv.x += finalOffset * stepLength; + } + + vec3 finalColor = textureLod(source_color, finalUv, 0.0).xyz * exposure * params.luminance_multiplier; + return finalColor; + +#endif } #endif // !SUBPASS