Files
qad/qglview/shaders/FXAA.frag

231 lines
9.2 KiB
GLSL

#version 130
in vec4 posPos;
uniform sampler2D tex0; // 0
//uniform float vx_offset;
uniform vec2 dt;
uniform float FXAA_SPAN_MAX = 8.;
uniform float FXAA_REDUCE_MUL = 1. / 8.;
#define FxaaInt2 ivec2
//#define vec2 vec2
vec3 FxaaPixelShader(vec4 posPos, // Output of FxaaVertexShader interpolated across screen.
sampler2D tex, // Input texture.
vec2 rcpFrame) { // Constant {1.0/frameWidth, 1.0/frameHeight}.
/*---------------------------------------------------------*/
// #define FXAA_REDUCE_MIN (1. / 128.)
#define FXAA_REDUCE_MIN (1. / 128.)
//#define FXAA_REDUCE_MUL (1.0/8.0)
//#define FXAA_SPAN_MAX 8.0
/*---------------------------------------------------------*/
vec3 rgbNW = texture2D(tex, posPos.zw).xyz;
vec3 rgbNE = textureOffset(tex, posPos.zw, ivec2(1, 0)).xyz;
vec3 rgbSW = textureOffset(tex, posPos.zw, ivec2(0, 1)).xyz;
vec3 rgbSE = textureOffset(tex, posPos.zw, ivec2(1, 1)).xyz;
vec3 rgbM = texture2D(tex, posPos.xy).xyz;
/*---------------------------------------------------------*/
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)));
/*---------------------------------------------------------*/
vec2 dir;
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
/*---------------------------------------------------------*/
float dirReduce = max(
(lumaNW + lumaNE + lumaSW + lumaSE) * (0.25 * FXAA_REDUCE_MUL),
FXAA_REDUCE_MIN);
float rcpDirMin = 1. / (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)) * rcpFrame.xy;
/*--------------------------------------------------------*/
vec3 rgbA = (1. / 2.) * (
texture2D(tex, posPos.xy + dir * (1. / 3. - 0.5)).xyz +
texture2D(tex, posPos.xy + dir * (2. / 3. - 0.5)).xyz);
vec3 rgbB = rgbA * (1. / 2.) + (1. / 4.) * (
texture2D(tex, posPos.xy + dir * (0. / 3. - 0.5)).xyz +
texture2D(tex, posPos.xy + dir * (3. / 3. - 0.5)).xyz);
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax)) return rgbA;
return rgbB;
}
vec3 Fxaa3PixelShader (
// {xy} = center of pixel
vec4 pos,
// {xyzw} = not used on FXAA3 Quality
//vec4 posPos,
// {rgb_} = color in linear or perceptual color space
// {__a} = luma in perceptual color space (not linear)
sampler2D tex,
// This must be from a constant/uniform.
// {x_} = 1.0/screenWidthInPixels
// {_y} = 1.0/screenHeightInPixels
vec2 rcpFrame
// {xyzw} = not used on FXAA3 Quality
//vec4 rcpFrameOpt
) {
/*--------------------------------------------------------------------------*/
//#if (FXAA_GATHER4_ALPHA == 1)
/*vec4 luma4A = FxaaTexOffAlpha4(tex, pos.xy, FxaaInt2(-1, -1), rcpFrame.xy);
#if (FXAA_DISCARD == 0)
vec4 rgbyM = texture2D(tex, pos.xy);
#endif
vec4 luma4B = FxaaTexAlpha4(tex, pos.xy, rcpFrame.xy);
float lumaNE = textureOffset(tex, pos.xy, ivec(1, -1)).w;
float lumaSW = textureOffset(tex, pos.xy, ivec(-1, 1)).w;
float lumaNW = luma4A.w;
float lumaN = luma4A.z;
float lumaW = luma4A.x;
float lumaM = luma4A.y;
float lumaE = luma4B.z;
float lumaS = luma4B.x;
float lumaSE = luma4B.y;*/
//#else
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaN = dot(textureLodOffset(tex, pos.xy, 0., ivec2(0, -1)).rgb, luma);
float lumaW = dot(textureLodOffset(tex, pos.xy, 0., ivec2(-1, 0)).rgb, luma);
vec4 rgbyM = texture2D(tex, pos.xy);
float lumaE = dot(textureLodOffset(tex, pos.xy, 0., ivec2( 1, 0)).rgb, luma);
float lumaS = dot(textureLodOffset(tex, pos.xy, 0., ivec2( 0, 1)).rgb, luma);
float lumaM = dot(rgbyM.rgb, luma);
//#endif
/*--------------------------------------------------------------------------*/
float rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE)));
float rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE)));
float range = rangeMax - rangeMin;
//return vec4(range);
/*--------------------------------------------------------------------------*/
#define FXAA_QUALITY_EDGE_THRESHOLD_MIN (1.0/12.0)
#define FXAA_QUALITY_EDGE_THRESHOLD (1.0/6.0)
if(range < max(FXAA_QUALITY_EDGE_THRESHOLD_MIN, rangeMax * FXAA_QUALITY_EDGE_THRESHOLD))
/*#if (FXAA_DISCARD == 1)
FxaaDiscard;
#else*/
return rgbyM.rgb;
//return vec3(0);
//#endif
/*--------------------------------------------------------------------------*/
//#if (FXAA_GATHER4_ALPHA == 0)
float lumaNW = dot(textureLodOffset(tex, pos.xy, 0., ivec2(-1,-1)).rgb, luma);
float lumaNE = dot(textureLodOffset(tex, pos.xy, 0., ivec2( 1,-1)).rgb, luma);
float lumaSW = dot(textureLodOffset(tex, pos.xy, 0., ivec2(-1, 1)).rgb, luma);
float lumaSE = dot(textureLodOffset(tex, pos.xy, 0., ivec2( 1, 1)).rgb, luma);
//#endif
/*--------------------------------------------------------------------------*/
#define FXAA_QUALITY_SUBPIX_CAP (3.0/4.0)
//#define FXAA_QUALITY_SUBPIX_CAP 0
#define FXAA_QUALITY_SUBPIX_TRIM (1.0/4.0)
#define FXAA_QUALITY_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_QUALITY_SUBPIX_TRIM))
/*--------------------------------------------------------------------------*/
float lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25;
float rangeL = abs(lumaL - lumaM);
float blendL = clamp((rangeL / range) - FXAA_QUALITY_SUBPIX_TRIM, 0., 1.) * FXAA_QUALITY_SUBPIX_TRIM_SCALE;
blendL = min(FXAA_QUALITY_SUBPIX_CAP, blendL);
/*--------------------------------------------------------------------------*/
float edgeVert =
abs(lumaNW + (-2.0 * lumaN) + lumaNE) +
10.0 * abs(lumaW + (-2.0 * lumaM) + lumaE ) +
abs(lumaSW + (-2.0 * lumaS) + lumaSE);
float edgeHorz =
abs(lumaNW + (-2.0 * lumaW) + lumaSW) +
10.0 * abs(lumaN + (-2.0 * lumaM) + lumaS ) +
abs(lumaNE + (-2.0 * lumaE) + lumaSE);
//return vec3(edgeHorz);
//float edgeVert = abs(lumaS - lumaN);
//float edgeHorz = abs(lumaE - lumaW);
bool horzSpan = edgeHorz >= edgeVert;
/*--------------------------------------------------------------------------*/
float lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x;
//if (edgeHorz == edgeVert) ;//lengthSign = 0.;
if(!horzSpan) {
lumaN = lumaW;
lumaS = lumaE;
}
float gradientN = abs(lumaN - lumaM);
float gradientS = abs(lumaS - lumaM);
lumaN = (lumaN + lumaM) * 0.5;
lumaS = (lumaS + lumaM) * 0.5;
/*--------------------------------------------------------------------------*/
bool pairN = gradientN >= gradientS;
if(!pairN) {
lumaN = lumaS;
gradientN = gradientS;
lengthSign = -lengthSign;
}
vec2 posN;
posN = pos.xy + (horzSpan ? vec2(0.0, lengthSign * 0.5) : vec2(lengthSign * 0.5, 0.0));
//posN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5);
//posN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0);
/*--------------------------------------------------------------------------*/
#define FXAA_SEARCH_STEPS 8
#define FXAA_SEARCH_THRESHOLD (1.0/8.0)
/*--------------------------------------------------------------------------*/
gradientN *= FXAA_SEARCH_THRESHOLD;
/*--------------------------------------------------------------------------*/
vec2 posP = posN;
vec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y);
float lumaEndN = 0.;
float lumaEndP = 0.;
bool doneN = false;
bool doneP = false;
posN += offNP * (-1.5);
posP += offNP * ( 1.5);
for(int i = 0; i < FXAA_SEARCH_STEPS; i++) {
lumaEndN = dot(texture2DLod(tex, posN.xy, 0.).rgb, luma);
lumaEndP = dot(texture2DLod(tex, posP.xy, 0.).rgb, luma);
bool doneN2 = abs(lumaEndN - lumaN) >= gradientN;
bool doneP2 = abs(lumaEndP - lumaN) >= gradientN;
if(doneN2 && !doneN) posN += offNP;
if(doneP2 && !doneP) posP -= offNP;
if(doneN2 && doneP2) break;
doneN = doneN2;
doneP = doneP2;
if(!doneN) posN -= offNP * 2.0;
if(!doneP) posP += offNP * 2.0;
}
/*--------------------------------------------------------------------------*/
float dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y;
float dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y;
/*--------------------------------------------------------------------------*/
bool directionN = dstN < dstP;
lumaEndN = directionN ? lumaEndN : lumaEndP;
/*--------------------------------------------------------------------------*/
if(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0))
lengthSign = 0.0;
/*--------------------------------------------------------------------------*/
float spanLength = (dstP + dstN);
dstN = directionN ? dstN : dstP;
float subPixelOffset = 0.5 + (dstN * (-1.0/spanLength));
subPixelOffset += blendL * (1.0/8.0);
subPixelOffset *= lengthSign;
vec3 rgbF = texture2DLod(tex, pos.xy + (horzSpan ? vec2(0., subPixelOffset) : vec2(subPixelOffset, 0.)), 0.).xyz;
/*--------------------------------------------------------------------------*/
/*#if (FXAA_LINEAR == 1)
lumaL *= lumaL;
#endif*/
float lumaF = dot(rgbF, vec3(0.299, 0.587, 0.114)) + (1.0/(65536.0*256.0));
float lumaB = mix(lumaF, lumaL, blendL);
float scale = min(4.0, lumaB/lumaF);
rgbF *= scale;
return vec3(rgbF);//, lumaM.rgb);
//, lumaM.rgb);
}
void main() {
gl_FragColor.rgb = Fxaa3PixelShader(posPos, tex0, dt);
}