LybOutlines/shaders/lib/antialiasing/fxaa.glsl

151 lines
6.2 KiB
Text
Raw Normal View History

2024-06-25 14:45:54 +02:00
//FXAA 3.11 from http://blog.simonrodriguez.fr/articles/30-07-2016_implementing_fxaa.html
float quality[12] = float[12] (1.0, 1.0, 1.0, 1.0, 1.0, 1.5, 2.0, 2.0, 2.0, 2.0, 4.0, 8.0);
void FXAA311(inout vec3 color) {
float edgeThresholdMin = 0.03125;
float edgeThresholdMax = 0.0625;
float subpixelQuality = 0.75;
int iterations = 12;
vec2 view = 1.0 / vec2(viewWidth, viewHeight);
float lumaCenter = GetLuminance(color);
float lumaDown = GetLuminance(texelFetch(colortex3, texelCoord + ivec2( 0, -1), 0).rgb);
float lumaUp = GetLuminance(texelFetch(colortex3, texelCoord + ivec2( 0, 1), 0).rgb);
float lumaLeft = GetLuminance(texelFetch(colortex3, texelCoord + ivec2(-1, 0), 0).rgb);
float lumaRight = GetLuminance(texelFetch(colortex3, texelCoord + ivec2( 1, 0), 0).rgb);
float lumaMin = min(lumaCenter, min(min(lumaDown, lumaUp), min(lumaLeft, lumaRight)));
float lumaMax = max(lumaCenter, max(max(lumaDown, lumaUp), max(lumaLeft, lumaRight)));
float lumaRange = lumaMax - lumaMin;
if (lumaRange > max(edgeThresholdMin, lumaMax * edgeThresholdMax)) {
float lumaDownLeft = GetLuminance(texelFetch(colortex3, texelCoord + ivec2(-1, -1), 0).rgb);
float lumaUpRight = GetLuminance(texelFetch(colortex3, texelCoord + ivec2( 1, 1), 0).rgb);
float lumaUpLeft = GetLuminance(texelFetch(colortex3, texelCoord + ivec2(-1, 1), 0).rgb);
float lumaDownRight = GetLuminance(texelFetch(colortex3, texelCoord + ivec2( 1, -1), 0).rgb);
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 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 stepLength = isHorizontal ? view.y : view.x;
float lumaLocalAverage = 0.0;
if (is1Steepest) {
stepLength = - stepLength;
lumaLocalAverage = 0.5 * (luma1 + lumaCenter);
} else {
lumaLocalAverage = 0.5 * (luma2 + lumaCenter);
}
vec2 currentUv = texCoord;
if (isHorizontal) {
currentUv.y += stepLength * 0.5;
} else {
currentUv.x += stepLength * 0.5;
}
vec2 offset = isHorizontal ? vec2(view.x, 0.0) : vec2(0.0, view.y);
vec2 uv1 = currentUv - offset;
vec2 uv2 = currentUv + offset;
float lumaEnd1 = GetLuminance(texture2D(colortex3, uv1).rgb);
float lumaEnd2 = GetLuminance(texture2D(colortex3, uv2).rgb);
lumaEnd1 -= lumaLocalAverage;
lumaEnd2 -= lumaLocalAverage;
bool reached1 = abs(lumaEnd1) >= gradientScaled;
bool reached2 = abs(lumaEnd2) >= gradientScaled;
bool reachedBoth = reached1 && reached2;
if (!reached1) {
uv1 -= offset;
}
if (!reached2) {
uv2 += offset;
}
if (!reachedBoth) {
for (int i = 2; i < iterations; i++) {
if (!reached1) {
lumaEnd1 = GetLuminance(texture2D(colortex3, uv1).rgb);
lumaEnd1 = lumaEnd1 - lumaLocalAverage;
}
if (!reached2) {
lumaEnd2 = GetLuminance(texture2D(colortex3, uv2).rgb);
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 ? (texCoord.x - uv1.x) : (texCoord.y - uv1.y);
float distance2 = isHorizontal ? (uv2.x - texCoord.x) : (uv2.y - texCoord.y);
bool isDirection1 = distance1 < distance2;
float distanceFinal = min(distance1, distance2);
float edgeThickness = (distance1 + distance2);
float pixelOffset = - distanceFinal / edgeThickness + 0.5;
bool isLumaCenterSmaller = lumaCenter < lumaLocalAverage;
bool correctVariation = ((isDirection1 ? lumaEnd1 : lumaEnd2) < 0.0) != isLumaCenterSmaller;
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 * subpixelQuality;
finalOffset = max(finalOffset, subPixelOffsetFinal);
// Compute the final UV coordinates.
vec2 finalUv = texCoord;
if (isHorizontal) {
finalUv.y += finalOffset * stepLength;
} else {
finalUv.x += finalOffset * stepLength;
}
color = texture2D(colortex3, finalUv).rgb;
}
}