declare const _default: "\n\nhighp float fractSinRand(const in vec2 uv) {\n    const float PI = 3.141592653589793;\n    const highp float a = 12.9898, b = 78.233, c = 43758.5453;\n    highp float dt = dot(uv.xy, vec2(a, b)), sn = mod(dt, PI);\n    return fract(sin(sn) * c);\n}\n\n// struct to hold precomputed constants and current state\nstruct VogelDiskData {\n    float invNumSamples;\n    float initialAngle;\n    float currentPointId;\n};\n\n// prepare the Vogel disk constants and initialize the current state in the struct\nvoid prepareDiskConstants(out VogelDiskData data, int sampleCount, float randomSeed) {\n    const float pi2 = 6.28318530718;\n    data.invNumSamples = 1.0 / float(sampleCount);\n    data.initialAngle = randomSeed * pi2;\n    data.currentPointId = 0.0;\n}\n\n\nvec2 generateDiskSample(inout VogelDiskData data) {\n    const float GOLDEN_ANGLE = 2.399963;\n    float r = sqrt((data.currentPointId + 0.5) * data.invNumSamples);\n    float theta = data.currentPointId * GOLDEN_ANGLE + data.initialAngle;\n\n    vec2 offset = vec2(cos(theta), sin(theta)) * pow(r, 1.33);\n\n    data.currentPointId += 1.0;\n    return offset;\n}\n\nvoid PCSSFindBlocker(TEXTURE_ACCEPT(shadowMap), out float avgBlockerDepth, out int numBlockers,\n    vec2 shadowCoords, float z, int shadowBlockerSamples, float searchWidthUv, float randomSeed) {\n\n    VogelDiskData diskData;\n    prepareDiskConstants(diskData, shadowBlockerSamples, randomSeed);\n\n    float blockerSum = 0.0;\n    numBlockers = 0;\n\n    for( int i = 0; i < shadowBlockerSamples; ++i ) {\n        vec2 diskUV = generateDiskSample(diskData);\n        vec2 sampleUV = shadowCoords + diskUV * searchWidthUv;\n        float shadowMapDepth = texture2DLod(shadowMap, sampleUV, 0.0).r;\n        if ( shadowMapDepth < z ) {\n            blockerSum += shadowMapDepth;\n            numBlockers++;\n        }\n    }\n    avgBlockerDepth = blockerSum / float(numBlockers);\n}\n\nfloat PCSSFilter(TEXTURE_ACCEPT(shadowMap), vec2 uv, float receiverDepth, int shadowSamples, float filterRadius, float randomSeed) {\n\n    VogelDiskData diskData;\n    prepareDiskConstants(diskData, shadowSamples, randomSeed);\n\n    float sum = 0.0;\n    for (int i = 0; i < shadowSamples; i++) {\n        vec2 offsetUV = generateDiskSample(diskData) * filterRadius;\n        float depth = texture2DLod(shadowMap, uv + offsetUV, 0.0).r;\n        sum += step(receiverDepth, depth);\n    }\n    return sum / float(shadowSamples);\n}\n\nfloat PCSSDirectional(TEXTURE_ACCEPT(shadowMap), vec3 shadowCoords, vec4 cameraParams, vec4 softShadowParams) {\n\n    float receiverDepth = shadowCoords.z;\n    // for sampling against the shadow map we clamp so cleared cells (depth = 1) don't get\n    // treated as blockers when the receiver sits outside the tightened cascade range.\n    // worldDist further down uses the *unclamped* receiverDepth so it stays cascade-stable.\n    float receiverDepthClamped = min(receiverDepth, 0.9999);\n    float randomSeed = fractSinRand(gl_FragCoord.xy);\n    int shadowSamples = int(softShadowParams.x);\n    int shadowBlockerSamples = int(softShadowParams.y);\n    float penumbraSize = softShadowParams.z;          // world-space \"area size of the light\"\n    float penumbraFalloff = softShadowParams.w;       // curve shape (>= 1)\n\n    // World-space PCSS. cameraParams.x is the ortho radius (world half-extent) of the\n    // directional shadow camera; cameraParams.y/z are far/near. Working in world units\n    // makes softness invariant to how the shadow camera tightens its depth bounds per\n    // light direction.\n    float orthoRadius = cameraParams.x;\n    float depthRange = cameraParams.y - cameraParams.z;\n    float worldPerUv = 2.0 * orthoRadius;\n\n    float filterRadius;\n\n    // contact hardening path\n    if (shadowBlockerSamples > 0) {\n\n        // search width bounds the largest possible penumbra (blocker at far end of depth range)\n        float searchWidthUv = (penumbraSize * depthRange) / worldPerUv;\n\n        float avgBlockerDepth = 0.0;\n        int numBlockers = 0;\n        PCSSFindBlocker(TEXTURE_PASS(shadowMap), avgBlockerDepth, numBlockers, shadowCoords.xy, receiverDepthClamped, shadowBlockerSamples, searchWidthUv, randomSeed);\n\n        // early out when no blockers are present\n        if (numBlockers < 1)\n            return 1.0f;\n\n        // World-space PCSS with shape control. The saturating curve reaches penumbraSize*depthRange\n        // when the blocker sits at the far end of the caster depth range; higher penumbraFalloff\n        // makes the softening climb faster (so the same blocker distance produces a wider penumbra).\n        // falloff=1 is the linear baseline.\n        float worldDist = max((receiverDepth - avgBlockerDepth) * depthRange, 0.0);\n        float t = clamp(worldDist / depthRange, 0.0, 1.0);\n        float shape = 1.0 - pow(1.0 - t, penumbraFalloff);\n        float penumbraWorld = shape * penumbraSize * depthRange;\n        filterRadius = penumbraWorld / worldPerUv;\n\n    } else {\n\n        // constant filter size, no contact hardening \u2014 penumbraSize is the world-space radius\n        filterRadius = penumbraSize / worldPerUv;\n    }\n\n    // filtering\n    return PCSSFilter(TEXTURE_PASS(shadowMap), shadowCoords.xy, receiverDepthClamped, shadowSamples, filterRadius, randomSeed);\n}\n\nfloat getShadowPCSS(TEXTURE_ACCEPT(shadowMap), vec3 shadowCoord, vec4 shadowParams, vec4 cameraParams, vec4 softShadowParams, vec3 lightDir) {\n    return PCSSDirectional(TEXTURE_PASS(shadowMap), shadowCoord, cameraParams, softShadowParams);\n}\n\n";
export default _default;
