declare const _default: "\n\n#include \"lightBufferDefinesPS\"\n\n// include this before shadow / cookie code\n#include \"clusteredLightUtilsPS\"\n\n#ifdef CLUSTER_COOKIES\n    #include \"clusteredLightCookiesPS\"\n#endif\n\n#ifdef CLUSTER_SHADOWS\n    #include \"clusteredLightShadowsPS\"\n#endif\n\nvar clusterWorldTexture: texture_2d<f32>;\nvar lightsTexture: texture_2d<f32>;\n\n#ifdef CLUSTER_SHADOWS\n    // TODO: when VSM shadow is supported, it needs to use sampler2D in webgl2\n    var shadowAtlasTexture: texture_depth_2d;\n    var shadowAtlasTextureSampler: sampler_comparison;\n#endif\n\n#ifdef CLUSTER_COOKIES\n    var cookieAtlasTexture: texture_2d<f32>;\n    var cookieAtlasTextureSampler: sampler;\n#endif\n\nuniform clusterMaxCells: i32;\n\n// 1.0 if clustered lighting can be skipped (0 lights in the clusters)\nuniform clusterSkip: f32;\n\nuniform clusterCellsCountByBoundsSize: vec3f;\nuniform clusterTextureSize: vec3f;\nuniform clusterBoundsMin: vec3f;\nuniform clusterBoundsDelta: vec3f;\nuniform clusterCellsDot: vec3f;\nuniform clusterCellsMax: vec3f;\nuniform shadowAtlasParams: vec2f;\n\n// structure storing light properties of a clustered light\n// it's sorted to have all vectors aligned to 4 floats to limit padding\nstruct ClusterLightData {\n\n    // 32bit of flags\n    flags: u32,\n\n    // area light sizes / orientation\n    halfWidth: vec3f,\n\n    isSpot: bool,\n\n    // area light sizes / orientation\n    halfHeight: vec3f,\n\n    // light index\n    lightIndex: i32,\n\n    // world space position\n    position: vec3f,\n\n    // area light shape\n    shape: u32,\n\n    // world space direction (spot light only)\n    direction: vec3f,\n\n    // light follow mode\n    falloffModeLinear: bool,\n\n    // color\n    color: vec3f,\n\n    // 0.0 if the light doesn't cast shadows\n    shadowIntensity: f32,\n\n    // atlas viewport for omni light shadow and cookie (.xy is offset to the viewport slot, .z is size of the face in the atlas)\n    omniAtlasViewport: vec3f,\n\n    // range of the light\n    range: f32,\n\n    // channel mask - one of the channels has 1, the others are 0\n    cookieChannelMask: vec4f,\n\n    // compressed biases, two haf-floats stored in a float\n    biasesData: f32,\n\n    // shadow bias values\n    shadowBias: f32,\n    shadowNormalBias: f32,\n\n    // compressed angles, two haf-floats stored in a float\n    anglesData: f32,\n\n    // spot light inner and outer angle cosine\n    innerConeAngleCos: f32,\n    outerConeAngleCos: f32,\n\n    // intensity of the cookie\n    cookieIntensity: f32,\n\n    // light mask\n    //float mask;\n    isDynamic: bool,\n    isLightmapped: bool\n}\n\n// Note: on some devices (tested on Pixel 3A XL), this matrix when stored inside the light struct has lower precision compared to\n// when stored outside, so we store it outside to avoid spot shadow flickering. This might need to be done to other / all members\n// of the structure if further similar issues are observed.\n\n// shadow (spot light only) / cookie projection matrix\nvar<private> lightProjectionMatrix: mat4x4f;\n\nfn sampleLightTextureF(lightIndex: i32, index: i32) -> vec4f {\n    return textureLoad(lightsTexture, vec2<i32>(index, lightIndex), 0);\n}\n\nfn decodeClusterLightCore(clusterLightData: ptr<function, ClusterLightData>, lightIndex: f32) {\n\n    // light index\n    clusterLightData.lightIndex = i32(lightIndex);\n\n    // sample data encoding half-float values into 32bit uints\n    let halfData: vec4f = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_COLOR_ANGLES_BIAS});\n\n    // store floats we decode later as needed\n    clusterLightData.anglesData = halfData.z;\n    clusterLightData.biasesData = halfData.w;\n\n    // decompress color half-floats\n    let colorRG: vec2f = unpack2x16float(bitcast<u32>(halfData.x));\n    let colorB_: vec2f = unpack2x16float(bitcast<u32>(halfData.y));\n    clusterLightData.color = vec3f(colorRG, colorB_.x) * {LIGHT_COLOR_DIVIDER};\n\n    // position and range, full floats\n    let lightPosRange: vec4f = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_POSITION_RANGE});\n    clusterLightData.position = lightPosRange.xyz;\n    clusterLightData.range = lightPosRange.w;\n\n    // spot direction & flags data\n    let lightDir_Flags: vec4f = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_DIRECTION_FLAGS});\n\n    // spot light direction\n    clusterLightData.direction = lightDir_Flags.xyz;\n\n    // 32bit flags\n    let flags_uint: u32 = bitcast<u32>(lightDir_Flags.w);\n    clusterLightData.flags = flags_uint;\n    clusterLightData.isSpot = (flags_uint & (1u << 30u)) != 0u;\n    clusterLightData.shape = (flags_uint >> 28u) & 0x3u;\n    clusterLightData.falloffModeLinear = (flags_uint & (1u << 27u)) == 0u;\n    clusterLightData.shadowIntensity = f32((flags_uint >> 0u) & 0xFFu) / 255.0;\n    clusterLightData.cookieIntensity = f32((flags_uint >> 8u) & 0xFFu) / 255.0;\n    clusterLightData.isDynamic = (flags_uint & (1u << 22u)) != 0u;\n    clusterLightData.isLightmapped = (flags_uint & (1u << 21u)) != 0u;\n}\n\nfn decodeClusterLightSpot(clusterLightData: ptr<function, ClusterLightData>) {\n    // spot light cos angles\n    let angles: vec2f = unpack2x16float(bitcast<u32>(clusterLightData.anglesData));\n    clusterLightData.innerConeAngleCos = angles.x;\n    clusterLightData.outerConeAngleCos = angles.y;\n}\n\nfn decodeClusterLightOmniAtlasViewport(clusterLightData: ptr<function, ClusterLightData>) {\n    clusterLightData.omniAtlasViewport = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_0}).xyz;\n}\n\nfn decodeClusterLightAreaData(clusterLightData: ptr<function, ClusterLightData>) {\n    clusterLightData.halfWidth = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_AREA_DATA_WIDTH}).xyz;\n    clusterLightData.halfHeight = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_AREA_DATA_HEIGHT}).xyz;\n}\n\nfn decodeClusterLightProjectionMatrixData(clusterLightData: ptr<function, ClusterLightData>) {\n    // shadow matrix\n    let m0: vec4f = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_0});\n    let m1: vec4f = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_1});\n    let m2: vec4f = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_2});\n    let m3: vec4f = sampleLightTextureF(clusterLightData.lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_3});\n    lightProjectionMatrix = mat4x4f(m0, m1, m2, m3);\n}\n\nfn decodeClusterLightShadowData(clusterLightData: ptr<function, ClusterLightData>) {\n    // shadow biases\n    let biases: vec2f = unpack2x16float(bitcast<u32>(clusterLightData.biasesData));\n    clusterLightData.shadowBias = biases.x;\n    clusterLightData.shadowNormalBias = biases.y;\n}\n\nfn decodeClusterLightCookieData(clusterLightData: ptr<function, ClusterLightData>) {\n\n    // extract channel mask from flags\n    let cookieFlags: u32 = (clusterLightData.flags >> 23u) & 0x0Fu;  // 4bits, each bit enables a channel\n    let mask_uvec: vec4<u32> = vec4<u32>(cookieFlags) & vec4<u32>(1u, 2u, 4u, 8u);\n    clusterLightData.cookieChannelMask = step(vec4f(1.0), vec4f(mask_uvec)); // Normalize to 0.0 or 1.0\n}\n\nfn evaluateLight(\n    light: ptr<function, ClusterLightData>,\n    worldNormal: vec3f,\n    viewDir: vec3f,\n    reflectionDir: vec3f,\n#if defined(LIT_CLEARCOAT)\n    clearcoatReflectionDir: vec3f,\n#endif\n    gloss: f32,\n    specularity: vec3f,\n    geometricNormal: vec3f,\n    tbn: mat3x3f,\n#if defined(LIT_IRIDESCENCE)\n    iridescenceFresnel: vec3f,\n#endif\n    clearcoat_worldNormal: vec3f,\n    clearcoat_gloss: f32,\n    sheen_gloss: f32,\n    iridescence_intensity: f32\n) {\n\n    var cookieAttenuation: vec3f = vec3f(1.0);\n    var diffuseAttenuation: f32 = 1.0;\n    var falloffAttenuation: f32 = 1.0;\n\n    // evaluate omni part of the light\n    let lightDirW: vec3f = evalOmniLight(light.position);\n    let lightDirNormW: vec3f = normalize(lightDirW);\n\n    #ifdef CLUSTER_AREALIGHTS\n\n    // distance attenuation\n    if (light.shape != {LIGHTSHAPE_PUNCTUAL}) { // area light\n\n        // area lights\n        decodeClusterLightAreaData(light);\n\n        // handle light shape\n        if (light.shape == {LIGHTSHAPE_RECT}) {\n            calcRectLightValues(light.position, light.halfWidth, light.halfHeight);\n        } else if (light.shape == {LIGHTSHAPE_DISK}) {\n            calcDiskLightValues(light.position, light.halfWidth, light.halfHeight);\n        } else { // sphere\n            calcSphereLightValues(light.position, light.halfWidth, light.halfHeight);\n        }\n\n        falloffAttenuation = getFalloffWindow(light.range, lightDirW);\n\n    } else\n\n    #endif\n\n    {   // punctual light\n\n        if (light.falloffModeLinear) {\n            falloffAttenuation = getFalloffLinear(light.range, lightDirW);\n        } else {\n            falloffAttenuation = getFalloffInvSquared(light.range, lightDirW);\n        }\n    }\n\n    if (falloffAttenuation > 0.00001) {\n\n        #ifdef CLUSTER_AREALIGHTS\n\n        if (light.shape != {LIGHTSHAPE_PUNCTUAL}) { // area light\n\n            // handle light shape\n            if (light.shape == {LIGHTSHAPE_RECT}) {\n                diffuseAttenuation = getRectLightDiffuse(worldNormal, viewDir, lightDirW, lightDirNormW) * 16.0;\n            } else if (light.shape == {LIGHTSHAPE_DISK}) {\n                diffuseAttenuation = getDiskLightDiffuse(worldNormal, viewDir, lightDirW, lightDirNormW) * 16.0;\n            } else { // sphere\n                diffuseAttenuation = getSphereLightDiffuse(worldNormal, viewDir, lightDirW, lightDirNormW) * 16.0;\n            }\n\n        } else\n\n        #endif\n\n        {\n            falloffAttenuation = falloffAttenuation * getLightDiffuse(worldNormal, viewDir, lightDirNormW);\n        }\n\n        // spot light falloff\n        if (light.isSpot) {\n            decodeClusterLightSpot(light);\n            falloffAttenuation = falloffAttenuation * getSpotEffect(light.direction, light.innerConeAngleCos, light.outerConeAngleCos, lightDirNormW);\n        }\n\n        #if defined(CLUSTER_COOKIES) || defined(CLUSTER_SHADOWS)\n\n        if (falloffAttenuation > 0.00001) {\n\n            // shadow / cookie\n            if (light.shadowIntensity > 0.0 || light.cookieIntensity > 0.0) {\n\n                // shared shadow / cookie data depends on light type\n                if (light.isSpot) {\n                    decodeClusterLightProjectionMatrixData(light);\n                } else {\n                    decodeClusterLightOmniAtlasViewport(light);\n                }\n\n                let shadowTextureResolution: f32 = uniform.shadowAtlasParams.x;\n                let shadowEdgePixels: f32 = uniform.shadowAtlasParams.y;\n\n                #ifdef CLUSTER_COOKIES\n\n                // cookie\n                if (light.cookieIntensity > 0.0) {\n                    decodeClusterLightCookieData(light);\n\n                    if (light.isSpot) {\n                        // !!!!!!!!!!! TEXTURE_PASS likely needs sampler. Assuming cookieAtlasTextureSampler exists.\n                        cookieAttenuation = getCookie2DClustered(cookieAtlasTexture, cookieAtlasTextureSampler, lightProjectionMatrix, vPositionW, light.cookieIntensity, light.cookieChannelMask);\n                    } else {\n                        // !!!!!!!!!!! TEXTURE_PASS likely needs sampler. Assuming cookieAtlasTextureSampler exists.\n                        cookieAttenuation = getCookieCubeClustered(cookieAtlasTexture, cookieAtlasTextureSampler, lightDirW, light.cookieIntensity, light.cookieChannelMask, shadowTextureResolution, shadowEdgePixels, light.omniAtlasViewport);\n                    }\n                }\n\n                #endif\n\n                #ifdef CLUSTER_SHADOWS\n\n                // shadow\n                if (light.shadowIntensity > 0.0) {\n                    decodeClusterLightShadowData(light);\n\n                    let shadowParams: vec4f = vec4f(shadowTextureResolution, light.shadowNormalBias, light.shadowBias, 1.0 / light.range);\n\n                    if (light.isSpot) {\n\n                        // spot shadow\n                        let shadowCoord: vec3f = getShadowCoordPerspZbufferNormalOffset(lightProjectionMatrix, shadowParams, geometricNormal);\n\n                        // !!!!!!!!!!! SHADOWMAP_PASS needs texture and sampler_comparison.\n                        // !!!!!!!!!!! Shadow functions need update for WGSL textureSampleCompare etc. Assuming these are handled in includes.\n                        #if defined(CLUSTER_SHADOW_TYPE_PCF1)\n                            let shadow: f32 = getShadowSpotClusteredPCF1(shadowAtlasTexture, shadowAtlasTextureSampler, shadowCoord, shadowParams);\n                        #elif defined(CLUSTER_SHADOW_TYPE_PCF3)\n                            let shadow: f32 = getShadowSpotClusteredPCF3(shadowAtlasTexture, shadowAtlasTextureSampler, shadowCoord, shadowParams);\n                        #elif defined(CLUSTER_SHADOW_TYPE_PCF5)\n                            let shadow: f32 = getShadowSpotClusteredPCF5(shadowAtlasTexture, shadowAtlasTextureSampler, shadowCoord, shadowParams);\n                        #elif defined(CLUSTER_SHADOW_TYPE_PCSS)\n                            let shadow: f32 = getShadowSpotClusteredPCSS(shadowAtlasTexture, shadowAtlasTextureSampler, shadowCoord, shadowParams);\n                        #endif\n                        falloffAttenuation = falloffAttenuation * mix(1.0, shadow, light.shadowIntensity);\n\n                    } else {\n\n                        // omni shadow\n                        let dir: vec3f = normalOffsetPointShadow(shadowParams, light.position, lightDirW, lightDirNormW, geometricNormal);  // normalBias adjusted for distance\n\n                        // !!!!!!!!!!! SHADOWMAP_PASS needs texture and sampler_comparison.\n                        // !!!!!!!!!!! Shadow functions need update for WGSL textureSampleCompare etc. Assuming these are handled in includes.\n                        #if defined(CLUSTER_SHADOW_TYPE_PCF1)\n                            let shadow: f32 = getShadowOmniClusteredPCF1(shadowAtlasTexture, shadowAtlasTextureSampler, shadowParams, light.omniAtlasViewport, shadowEdgePixels, dir);\n                        #elif defined(CLUSTER_SHADOW_TYPE_PCF3)\n                            let shadow: f32 = getShadowOmniClusteredPCF3(shadowAtlasTexture, shadowAtlasTextureSampler, shadowParams, light.omniAtlasViewport, shadowEdgePixels, dir);\n                        #elif defined(CLUSTER_SHADOW_TYPE_PCF5)\n                            let shadow: f32 = getShadowOmniClusteredPCF5(shadowAtlasTexture, shadowAtlasTextureSampler, shadowParams, light.omniAtlasViewport, shadowEdgePixels, dir);\n                        #endif\n                        falloffAttenuation = falloffAttenuation * mix(1.0, shadow, light.shadowIntensity);\n                    }\n                }\n\n                #endif\n            }\n        }\n\n        #endif\n\n        // diffuse / specular / clearcoat\n        #ifdef CLUSTER_AREALIGHTS\n\n        if (light.shape != {LIGHTSHAPE_PUNCTUAL}) { // area light\n\n            // area light diffuse\n            {\n                var areaDiffuse: vec3f = (diffuseAttenuation * falloffAttenuation) * light.color * cookieAttenuation;\n\n                #if defined(LIT_SPECULAR)\n                    areaDiffuse = mix(areaDiffuse, vec3f(0.0), dLTCSpecFres);\n                #endif\n\n                // area light diffuse - it does not mix diffuse lighting into specular attenuation\n                dDiffuseLight = dDiffuseLight + areaDiffuse;\n            }\n\n            // specular and clear coat are material settings and get included by a define based on the material\n            #ifdef LIT_SPECULAR\n\n                // area light specular\n                var areaLightSpecular: f32; // Use var because assigned in if/else\n\n                if (light.shape == {LIGHTSHAPE_RECT}) {\n                    areaLightSpecular = getRectLightSpecular(worldNormal, viewDir);\n                } else if (light.shape == {LIGHTSHAPE_DISK}) {\n                    areaLightSpecular = getDiskLightSpecular(worldNormal, viewDir);\n                } else { // sphere\n                    areaLightSpecular = getSphereLightSpecular(worldNormal, viewDir);\n                }\n\n                dSpecularLight = dSpecularLight + dLTCSpecFres * areaLightSpecular * falloffAttenuation * light.color * cookieAttenuation;\n\n                #ifdef LIT_CLEARCOAT\n\n                    // area light specular clear coat\n                    var areaLightSpecularCC: f32; // Use var because assigned in if/else\n\n                    if (light.shape == {LIGHTSHAPE_RECT}) {\n                        areaLightSpecularCC = getRectLightSpecular(clearcoat_worldNormal, viewDir);\n                    } else if (light.shape == {LIGHTSHAPE_DISK}) {\n                        areaLightSpecularCC = getDiskLightSpecular(clearcoat_worldNormal, viewDir);\n                    } else { // sphere\n                        areaLightSpecularCC = getSphereLightSpecular(clearcoat_worldNormal, viewDir);\n                    }\n\n                    ccSpecularLight = ccSpecularLight + ccLTCSpecFres * areaLightSpecularCC * falloffAttenuation * light.color  * cookieAttenuation;\n\n                #endif\n\n            #endif\n\n        } else\n\n        #endif\n\n        {    // punctual light\n\n            // punctual light diffuse\n            {\n                var punctualDiffuse: vec3f = falloffAttenuation * light.color * cookieAttenuation;\n\n                #if defined(CLUSTER_AREALIGHTS)\n                #if defined(LIT_SPECULAR)\n                    punctualDiffuse = mix(punctualDiffuse, vec3f(0.0), specularity);\n                #endif\n                #endif\n\n                dDiffuseLight = dDiffuseLight + punctualDiffuse;\n            }\n\n            // specular and clear coat are material settings and get included by a define based on the material\n            #ifdef LIT_SPECULAR\n\n                let halfDir: vec3f = normalize(-lightDirNormW + viewDir);\n\n                // specular\n                #ifdef LIT_SPECULAR_FRESNEL\n                    dSpecularLight = dSpecularLight +\n                        getLightSpecular(halfDir, reflectionDir, worldNormal, viewDir, lightDirNormW, gloss, tbn) * falloffAttenuation * light.color * cookieAttenuation *\n                        getFresnel(\n                            dot(viewDir, halfDir),\n                            gloss,\n                            specularity\n                        #if defined(LIT_IRIDESCENCE)\n                            , iridescenceFresnel,\n                            iridescence_intensity\n                        #endif\n                            );\n                #else\n                    dSpecularLight = dSpecularLight + getLightSpecular(halfDir, reflectionDir, worldNormal, viewDir, lightDirNormW, gloss, tbn) * falloffAttenuation * light.color * cookieAttenuation * specularity;\n                #endif\n\n                #ifdef LIT_CLEARCOAT\n                    #ifdef LIT_SPECULAR_FRESNEL\n                        ccSpecularLight = ccSpecularLight + getLightSpecular(halfDir, clearcoatReflectionDir, clearcoat_worldNormal, viewDir, lightDirNormW, clearcoat_gloss, tbn) * falloffAttenuation * light.color * cookieAttenuation * getFresnelCC(dot(viewDir, halfDir));\n                    #else\n                        ccSpecularLight = ccSpecularLight + getLightSpecular(halfDir, clearcoatReflectionDir, clearcoat_worldNormal, viewDir, lightDirNormW, clearcoat_gloss, tbn) * falloffAttenuation * light.color * cookieAttenuation;\n                    #endif\n                #endif\n\n                #ifdef LIT_SHEEN\n                    sSpecularLight = sSpecularLight + getLightSpecularSheen(halfDir, worldNormal, viewDir, lightDirNormW, sheen_gloss) * falloffAttenuation * light.color * cookieAttenuation;\n                #endif\n\n            #endif\n        }\n    }\n\n    // Write to global attenuation values (for lightmapper)\n    dAtten = falloffAttenuation;\n    dLightDirNormW = lightDirNormW;\n}\n\n\nfn evaluateClusterLight(\n    lightIndex: f32,\n    worldNormal: vec3f,\n    viewDir: vec3f,\n    reflectionDir: vec3f,\n#if defined(LIT_CLEARCOAT)\n    clearcoatReflectionDir: vec3f,\n#endif\n    gloss: f32,\n    specularity: vec3f,\n    geometricNormal: vec3f,\n    tbn: mat3x3f,\n#if defined(LIT_IRIDESCENCE)\n    iridescenceFresnel: vec3f,\n#endif\n    clearcoat_worldNormal: vec3f,\n    clearcoat_gloss: f32,\n    sheen_gloss: f32,\n    iridescence_intensity: f32\n) {\n\n    // decode core light data from textures\n    var clusterLightData: ClusterLightData;\n    decodeClusterLightCore(&clusterLightData, lightIndex);\n\n    // evaluate light if it uses accepted light mask\n    #ifdef CLUSTER_MESH_DYNAMIC_LIGHTS\n        let acceptLightMask: bool = clusterLightData.isDynamic;\n    #else\n        let acceptLightMask: bool = clusterLightData.isLightmapped;\n    #endif\n\n    if (acceptLightMask) {\n        evaluateLight(\n            &clusterLightData,\n            worldNormal,\n            viewDir,\n            reflectionDir,\n#if defined(LIT_CLEARCOAT)\n            clearcoatReflectionDir,\n#endif\n            gloss,\n            specularity,\n            geometricNormal,\n            tbn,\n#if defined(LIT_IRIDESCENCE)\n            iridescenceFresnel,\n#endif\n            clearcoat_worldNormal,\n            clearcoat_gloss,\n            sheen_gloss,\n            iridescence_intensity\n        );\n    }\n}\n\n\nfn addClusteredLights(\n    worldNormal: vec3f,\n    viewDir: vec3f,\n    reflectionDir: vec3f,\n#if defined(LIT_CLEARCOAT)\n    clearcoatReflectionDir: vec3f,\n#endif\n    gloss: f32,\n    specularity: vec3f,\n    geometricNormal: vec3f,\n    tbn: mat3x3f,\n#if defined(LIT_IRIDESCENCE)\n    iridescenceFresnel: vec3f,\n#endif\n    clearcoat_worldNormal: vec3f,\n    clearcoat_gloss: f32,\n    sheen_gloss: f32,\n    iridescence_intensity: f32\n) {\n\n    // skip lights if no lights at all\n    if (uniform.clusterSkip > 0.5) {\n        return;\n    }\n\n    // world space position to 3d integer cell cordinates in the cluster structure\n    let cellCoords: vec3f = floor((vPositionW - uniform.clusterBoundsMin) * uniform.clusterCellsCountByBoundsSize);\n\n    // no lighting when cell coordinate is out of range\n    if (!(any(cellCoords < vec3f(0.0)) || any(cellCoords >= uniform.clusterCellsMax))) {\n\n        // cell index (mapping from 3d cell coordinates to linear memory)\n        let cellIndex: f32 = dot(uniform.clusterCellsDot, cellCoords);\n\n        // convert cell index to uv coordinates\n        let clusterV: f32 = floor(cellIndex * uniform.clusterTextureSize.y);\n        let clusterU: f32 = cellIndex - (clusterV * uniform.clusterTextureSize.x);\n\n        // loop over maximum number of light cells\n        for (var lightCellIndex: i32 = 0; lightCellIndex < uniform.clusterMaxCells; lightCellIndex = lightCellIndex + 1) {\n\n            // using a single channel texture with data in red channel\n            let lightIndexPacked: f32 = textureLoad(clusterWorldTexture, vec2<i32>(i32(clusterU) + lightCellIndex, i32(clusterV)), 0).r;\n\n            if (lightIndexPacked <= 0.0) {\n                break;\n            }\n\n            evaluateClusterLight(\n                lightIndexPacked * 255.0,\n                worldNormal,\n                viewDir,\n                reflectionDir,\n#if defined(LIT_CLEARCOAT)\n                clearcoatReflectionDir,\n#endif\n                gloss,\n                specularity,\n                geometricNormal,\n                tbn,\n#if defined(LIT_IRIDESCENCE)\n                iridescenceFresnel,\n#endif\n                clearcoat_worldNormal,\n                clearcoat_gloss,\n                sheen_gloss,\n                iridescence_intensity\n            );\n        }\n    }\n}";
export default _default;
