LYGIA Shader Library

fxaa (lygia/sample/fxaa)

Basic FXAA implementation based on the code on geeks3d.com with the modification that the texture2DLod stuff was removed since it's unsupported by WebGL from https://github.com/mitsuhiko/webgl-meincraft

Dependencies:

Use:

sampleFXAA(<SAMPLER_TYPE> tex, <vec2> st, <vec2> pixel)

Check it on Github



#ifndef SAMPLEFXAA_REDUCE_MIN
#define SAMPLEFXAA_REDUCE_MIN   (1.0/128.0)
#endif

#ifndef SAMPLEFXAA_REDUCE_MUL
#define SAMPLEFXAA_REDUCE_MUL   (1.0/8.0)
#endif

#ifndef SAMPLEFXAA_SPAN_MAX
#define SAMPLEFXAA_SPAN_MAX     8.0
#endif

#ifndef SAMPLEFXAA_SAMPLE_FNC
#define SAMPLEFXAA_SAMPLE_FNC(TEX, UV) SAMPLER_FNC(TEX, UV)
#endif

#ifndef FNC_SAMPLEFXAA
#define FNC_SAMPLEFXAA 
vec4 sampleFXAA(SAMPLER_TYPE tex, vec2 uv, vec2 pixel) {
    vec3 rgbNW  = SAMPLEFXAA_SAMPLE_FNC(tex,uv.xy + vec2( -1.0, -1.0 ) * pixel).xyz;
    vec3 rgbNE  = SAMPLEFXAA_SAMPLE_FNC(tex,uv.xy + vec2( 1.0, -1.0 ) * pixel).xyz;
    vec3 rgbSW  = SAMPLEFXAA_SAMPLE_FNC(tex,uv.xy + vec2( -1.0, 1.0 ) * pixel).xyz;
    vec3 rgbSE  = SAMPLEFXAA_SAMPLE_FNC(tex,uv.xy + vec2( 1.0, 1.0 ) * pixel).xyz;
    vec4 rgbaM  = SAMPLEFXAA_SAMPLE_FNC(tex,uv.xy  * pixel);
    vec3 rgbM   = rgbaM.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 = vec2(-((lumaNW + lumaNE) - (lumaSW + lumaSE)),
                     ((lumaNW + lumaSW) - (lumaNE + lumaSE)) );

    float dirReduce = max(  ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * SAMPLEFXAA_REDUCE_MUL ), 
                            SAMPLEFXAA_REDUCE_MIN );
    float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );
    dir = min( vec2(SAMPLEFXAA_SPAN_MAX,  SAMPLEFXAA_SPAN_MAX),
                max(vec2(-SAMPLEFXAA_SPAN_MAX, -SAMPLEFXAA_SPAN_MAX),
                    dir * rcpDirMin)) * pixel;

    vec4 rgbA = 0.5 * ( SAMPLEFXAA_SAMPLE_FNC(tex, uv.xy + dir * (1.0/3.0 - 0.5)) +
                        SAMPLEFXAA_SAMPLE_FNC(tex, uv.xy + dir * (2.0/3.0 - 0.5)) );
    vec4 rgbB = rgbA * 0.5 + 0.25 * (
                        SAMPLEFXAA_SAMPLE_FNC(tex, uv.xy + dir * -0.5) +
                        SAMPLEFXAA_SAMPLE_FNC(tex, uv.xy + dir * 0.5) );

    float lumaB = dot(rgbB, vec4(luma, 0.0));
    if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) )
        return rgbA;
    else
        return rgbB;
}

#endif

Dependencies:

Use:

sampleFXAA(<SAMPLER_TYPE> tex, <float2> st, <float2> pixel)

Check it on Github



#ifndef SAMPLEFXAA_REDUCE_MIN
#define SAMPLEFXAA_REDUCE_MIN   (1.0/128.0)
#endif

#ifndef SAMPLEFXAA_REDUCE_MUL
#define SAMPLEFXAA_REDUCE_MUL   (1.0/8.0)
#endif

#ifndef SAMPLEFXAA_SPAN_MAX
#define SAMPLEFXAA_SPAN_MAX     8.0
#endif

#ifndef SAMPLEFXAA_SAMPLE_FNC
#define SAMPLEFXAA_SAMPLE_FNC(UV) SAMPLER_FNC(tex, UV)
#endif

#ifndef FNC_SAMPLEFXAA
#define FNC_SAMPLEFXAA 
float4 sampleFXAA(SAMPLER_TYPE tex, float2 uv, float2 pixel) {
    float3 rgbNW  = SAMPLEFXAA_SAMPLE_FNC(uv.xy + float2( -1.0, -1.0 ) * pixel).xyz;
    float3 rgbNE  = SAMPLEFXAA_SAMPLE_FNC(uv.xy + float2( 1.0, -1.0 ) * pixel).xyz;
    float3 rgbSW  = SAMPLEFXAA_SAMPLE_FNC(uv.xy + float2( -1.0, 1.0 ) * pixel).xyz;
    float3 rgbSE  = SAMPLEFXAA_SAMPLE_FNC(uv.xy + float2( 1.0, 1.0 ) * pixel).xyz;
    float4 rgbaM  = SAMPLEFXAA_SAMPLE_FNC(uv.xy  * pixel);
    float3 rgbM   = rgbaM.xyz;
    float3 luma   = float3( 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 ) ) );
    float2 dir = float2(-((lumaNW + lumaNE) - (lumaSW + lumaSE)),
                     ((lumaNW + lumaSW) - (lumaNE + lumaSE)) );

    float dirReduce = max(  ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * SAMPLEFXAA_REDUCE_MUL ), 
                            SAMPLEFXAA_REDUCE_MIN );
    float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );
    dir = min( float2(SAMPLEFXAA_SPAN_MAX,  SAMPLEFXAA_SPAN_MAX),
                max(float2(-SAMPLEFXAA_SPAN_MAX, -SAMPLEFXAA_SPAN_MAX),
                    dir * rcpDirMin)) * pixel;

    float4 rgbA = 0.5 * (   SAMPLEFXAA_SAMPLE_FNC( uv.xy + dir * (1.0/3.0 - 0.5)) +
                            SAMPLEFXAA_SAMPLE_FNC( uv.xy + dir * (2.0/3.0 - 0.5)) );
    float4 rgbB = rgbA * 0.5 + 0.25 * ( SAMPLEFXAA_SAMPLE_FNC( uv.xy + dir * -0.5) +
                                        SAMPLEFXAA_SAMPLE_FNC( uv.xy + dir * 0.5) );

    float lumaB = dot(rgbB, float4(luma, 0.0));
    if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) )
        return rgbA;
    else
        return rgbB;
}

#endif

Licenses

LYGIA is dual-licensed under the Prosperity License and the Patron License for sponsors and contributors.

Sponsors and contributors are automatically added to the Patron License and they can ignore the any non-commercial rule of the Prosperity Licensed software (please take a look to the exception).

It's also possible to get a permanent comercial license hook to a single and specific version of LYGIA.

Get the latest news and releases

Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository