#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); }