float SF_fast2D(in sampler2DShadow shadowtex, in vec3 wPos) {
    const float step = 1.0/shadowMapResolution;
    float noise     = ditherGradNoise()*pi;
    vec2 offset     = vec2(cos(noise), sin(noise))*step;
    float shade     = shadow2DLod(shadowtex, vec3(wPos.xy+offset, wPos.z), 0).x;
        shade      += shadow2DLod(shadowtex, vec3(wPos.xy-offset, wPos.z), 0).x;
        shade      += shadow2DLod(shadowtex, wPos.xyz, 0).x*0.5;
    return shade*0.4;
}
vec4 SFcol_fast2D(in sampler2D shadowtex, in vec3 wPos) {
    const float step = 1.0/shadowMapResolution;
    float noise     = ditherGradNoise()*pi;
    vec2 offset     = vec2(cos(noise), sin(noise))*step;
    vec4 shade     = texture2D(shadowtex, wPos.xy+offset);
        shade      += texture2D(shadowtex, wPos.xy-offset);
        shade      += texture2D(shadowtex, wPos.xy)*0.5;
    return shade*0.4;
}

float SF_low2D(in vec3 pos, in float sigma, out vec4 col) { //using 15 tap poisson
    float shadow    = 0.0;
    col             = vec4(1.0, 1.0, 1.0, 0.0);
    vec2 dither     = taaShadowDither();

    for (int i = 0; i<15; i++) {
        vec2 coord      = pos.xy + poisson60o[i*4]*dither*sigma;
        float depth1    = shadow2DLod(shadowtex1, vec3(coord, pos.z), 0).x;
        shadow         += depth1;

        float depth0 = shadow2DLod(shadowtex0, vec3(coord, pos.z), 0).x;
        bool translucency = depth1>depth0;
        if (translucency) {
                vec4 scol   = textureLod(shadowcolor0, coord, 0);
            col.rgb     = min(col.rgb, scol.rgb*0.9);
            col.a       = max(col.a, scol.a);
        }
    }
    shadow /= 15.0;
    return shadow;
}
float SF_med2D(in vec3 pos, in float sigma, out vec4 col) { //using 30 tap poisson
    float shadow    = 0.0;
    col             = vec4(1.0, 1.0, 1.0, 0.0);
    vec2 dither     = taaShadowDither();

    for (int i = 0; i<30; i++) {
        vec2 coord  = pos.xy + poisson60o[i*2]*dither*sigma;
        float depth1    = shadow2DLod(shadowtex1, vec3(coord, pos.z), 0).x;
        shadow     += depth1;

        if (i%3 == 0) {
            float depth0 = shadow2DLod(shadowtex0, vec3(coord, pos.z), 0).x;
            bool translucency = depth1>depth0;
            if (translucency) {
                vec4 scol   = textureLod(shadowcolor0, coord, 0);
                col.rgb     = min(col.rgb, scol.rgb*0.9);
                col.a       = max(col.a, scol.a);
            }
        }
    }
    shadow /= 30.0;
    return shadow;
}

void getShadow2DSoft(in vec3 pos, in float distortion, inout float shadow, inout vec4 shadowcol) {
    #if shadowFilterQuality==0
        shadow  = SF_fast2D(shadowtex1, pos);
        shadowcol = SFcol_fast2D(shadowcolor0, pos);
    #elif shadowFilterQuality==1
        shadow  = SF_low2D(pos, 0.0002*distortion, shadowcol);
    #elif shadowFilterQuality==2
        shadow  = SF_med2D(pos, 0.0002*distortion, shadowcol);
    #endif
}