float SFpcss_low(in vec3 pos, in float sigma, in float cdepth, const float diff, 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    = textureLod(shadowtex1, coord, 0).x;
        float temp1     = 1.0-clamp(cdepth-depth1*256.0, 0.0, diff)/diff;
        shadow     += temp1;

        float depth0 = textureLod(shadowtex0, coord, 0).x;
        float temp0  = 1.0-clamp(cdepth-depth0*256.0, 0.0, diff)/diff;
        bool translucency = temp1>temp0;
        if (translucency) {
                vec4 scol   = textureLod(shadowcolor0, coord, 0);
            col.rgb     = min(col.rgb, scol.rgb*0.9);
            col.a       = max(col.a, scol.s);
        }
    }
    shadow /= 15.0;
    return shadow;
}
float SFpcss_med(in vec3 pos, in float sigma, in float cdepth, const float diff, 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    = textureLod(shadowtex1, coord, 0).x;
        float temp1     = 1.0-clamp(cdepth-depth1*256.0, 0.0, diff)/diff;
        shadow     += temp1;

        if (i%2 == 0) {
            float depth0 = textureLod(shadowtex0, coord, 0).x;
            float temp0  = 1.0-clamp(cdepth-depth0*256.0, 0.0, diff)/diff;
            bool translucency = temp1>temp0;
            if (translucency) {
                vec4 scol   = textureLod(shadowcolor0, coord, 0);
                col.rgb     = min(col.rgb, scol.rgb*0.9);
                col.a       = max(col.a, scol.s);
            }
        }
    }
    shadow /= 30.0;
    return shadow;
}
float SFpcss_high(in vec3 pos, in float sigma, in float cdepth, const float diff, out vec4 col) { //using 60 tap poisson
    float shadow    = 0.0;
    col             = vec4(1.0, 1.0, 1.0, 0.0);
    vec2 dither     = taaShadowDither();

    for (int i = 0; i<60; i++) {
        vec2 coord      = pos.xy + poisson60o[i]*dither*sigma;
        float depth1    = textureLod(shadowtex1, coord, 0).x;
        float temp1     = 1.0-clamp(cdepth-depth1*256.0, 0.0, diff)/diff;
        shadow     += temp1;

        if (i%3 == 0) {
            float depth0 = textureLod(shadowtex0, coord, 0).x;
            float temp0  = 1.0-clamp(cdepth-depth0*256.0, 0.0, diff)/diff;
            bool translucency = temp1>temp0;
            if (translucency) {
                vec4 scol   = textureLod(shadowcolor0, coord, 0);
                col.rgb     = min(col.rgb, scol.rgb*0.9);
                col.a       = max(col.a, scol.s);
            }
        }
    }
    shadow /= 30.0;
    return shadow;
}

float pcssSigma(in vec3 pos, in float cdepth) {
    const float lightSize = 0.04*pcssArea;
    const int samples = pcssSamples;
    const float minSigma = 0.00006;
    float zcoord    = pos.z;
    float dist      = 0.0;
    float sigma     = 0.0;
    float shadowDepth = 0.0;
    float blockers  = 0.0;

    float searchArea = lightSize/zcoord;
        searchArea *= 1.2;

    for (int i = -samples; i<samples; i++) {
        for (int j = -samples; j<samples; j++) {
            vec2 searchCoord = pos.xy + (vec2(i, j) * searchArea / (20*samples));
            shadowDepth     = textureLod(shadowtex0, searchCoord, 2).x;

            dist    += shadowDepth;
            blockers += 1.0;
        }
    }

    if (blockers > 0.0) {
        dist /= blockers;
        sigma = (zcoord-dist)*lightSize / zcoord;
    }
    
    return clamp(max(sigma, minSigma), 0.0, searchArea/20);
}

void getShadowPCSS(in vec3 pos, in float cdepth, in float distortion, inout float shadow, inout vec4 shadowcol, in float cdepth2) {
    float sigma     = pcssSigma(pos.xyz, cdepth)*distortion;
    
    #if shadowFilterQuality==0
        shadow          = SFpcss_low(pos, sigma, cdepth, 0.06, shadowcol);
    #elif shadowFilterQuality==1
        shadow          = SFpcss_med(pos, sigma, cdepth, 0.06, shadowcol);
    #elif shadowFilterQuality==2
        shadow          = SFpcss_high(pos, sigma, cdepth, 0.06, shadowcol);
    #endif
}