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<u32>;\nvar lightsTexture: texture_2d<uff>;\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// number of lights in the cluster structure\nuniform numClusteredLights: i32;\n\n// width of the cluster texture\nuniform clusterTextureWidth: i32;\n\nuniform clusterCellsCountByBoundsSize: vec3f;\nuniform clusterBoundsMin: vec3f;\nuniform clusterBoundsDelta: vec3f;\nuniform clusterCellsDot: vec3i;\nuniform clusterCellsMax: vec3i;\nuniform shadowAtlasParams: vec2f;\n\n// structure storing light properties of a clustered light. Vectors and scalars are interleaved\n// so each vec3 packs with an adjacent 4-byte field into a 16-byte slot, minimising padding for\n// compilers that don't reorder struct members.\nstruct ClusterLightData {\n\n    // world space position\n    position: vec3f,\n\n    // light index in the lights texture\n    lightIndex: i32,\n\n    // world space direction (spot light only)\n    direction: vec3f,\n\n    // area light shape\n    shape: u32,\n\n    // color\n    color: vec3f,\n\n    // 0.0 if the light doesn't cast shadows\n    shadowIntensity: f32,\n\n    // range of the light\n    range: f32,\n\n    // compressed biases, two half-floats stored in a float\n    biasesData: f32,\n\n    // intensity of the cookie\n    cookieIntensity: f32,\n\n    // true for spot lights\n    isSpot: bool,\n\n    // light follow mode\n    falloffModeLinear: bool,\n\n    // light mask (mutually exclusive)\n    isDynamic: bool,\n    isLightmapped: bool\n}\n\n// Spot light cone angles, decoded on demand only when the light is a spot light.\nstruct ClusterLightSpotData {\n    innerConeAngleCos: f32,\n    outerConeAngleCos: f32\n}\n\n// Area light dimensions and orientation, decoded on demand only for non-punctual lights.\nstruct ClusterLightAreaData {\n    halfWidth: vec3f,\n    halfHeight: vec3f\n}\n\n// Shadow bias parameters, decoded on demand only when the light casts shadows.\nstruct ClusterLightShadowData {\n    shadowBias: f32,\n    shadowNormalBias: f32\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\n// NOTE: On some Samsung devices, these values can suffer precision / corruption issues when stored\n// as members of ClusterLightData. Keep them as module-scope temporaries instead. See issue #7800.\nvar<private> clusterLightData_flags: u32;             // 32bit of flags\nvar<private> clusterLightData_anglesData: f32;        // compressed angles, two half-floats stored in a float\nvar<private> clusterLightData_colorBFlagsData: u32;   // blue color component and angle flags (as uint for efficient bit operations)\n\nfn sampleLightTextureF(lightIndex: i32, index: i32) -> vec4f {\n    return textureLoad(lightsTexture, vec2<i32>(index, lightIndex), 0);\n}\n\nfn decodeClusterLightCore(lightIndex: i32) -> ClusterLightData {\n    var clusterLightData: ClusterLightData;\n\n    // light index\n    clusterLightData.lightIndex = lightIndex;\n\n    // sample data encoding half-float values into 32bit uints\n    let halfData: vec4f = sampleLightTextureF(lightIndex, {CLUSTER_TEXTURE_COLOR_ANGLES_BIAS});\n\n    // store values needed by later decode steps (anglesData / colorBFlagsData live outside the\n    // struct due to Samsung precision issues - see #7800)\n    clusterLightData_anglesData = halfData.z;\n    clusterLightData.biasesData = halfData.w;\n    clusterLightData_colorBFlagsData = bitcast<u32>(halfData.y);\n\n    // decompress color half-floats\n    let colorRG: vec2f = unpack2x16float(bitcast<u32>(halfData.x));\n    let colorB_flags: vec2f = unpack2x16float(clusterLightData_colorBFlagsData);\n    clusterLightData.color = vec3f(colorRG, colorB_flags.x) * {LIGHT_COLOR_DIVIDER};\n\n    // position and range, full floats\n    let lightPosRange: vec4f = sampleLightTextureF(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(lightIndex, {CLUSTER_TEXTURE_DIRECTION_FLAGS});\n\n    // spot light direction\n    clusterLightData.direction = lightDir_Flags.xyz;\n\n    // 32bit flags (kept outside the struct, see #7800)\n    clusterLightData_flags = bitcast<u32>(lightDir_Flags.w);\n    clusterLightData.isSpot = (clusterLightData_flags & (1u << 30u)) != 0u;\n    clusterLightData.shape = (clusterLightData_flags >> 28u) & 0x3u;\n    clusterLightData.falloffModeLinear = (clusterLightData_flags & (1u << 27u)) == 0u;\n    clusterLightData.shadowIntensity = f32((clusterLightData_flags >> 0u) & 0xFFu) / 255.0;\n    clusterLightData.cookieIntensity = f32((clusterLightData_flags >> 8u) & 0xFFu) / 255.0;\n    clusterLightData.isDynamic = (clusterLightData_flags & (1u << 22u)) != 0u;\n    clusterLightData.isLightmapped = (clusterLightData_flags & (1u << 21u)) != 0u;\n\n    return clusterLightData;\n}\n\nfn decodeClusterLightSpot() -> ClusterLightSpotData {\n    // decompress spot light angles\n    let angleFlags: u32 = (clusterLightData_colorBFlagsData >> 16u) & 0xFFFFu;  // Extract upper 16 bits as integer\n\n    let angleValues: vec2f = unpack2x16float(bitcast<u32>(clusterLightData_anglesData));\n    let innerVal: f32 = angleValues.x;\n    let outerVal: f32 = angleValues.y;\n\n    // decode based on flags (branch-free)\n    let innerIsVersine: bool = (angleFlags & 1u) != 0u;      // bit 0: inner angle format\n    let outerIsVersine: bool = ((angleFlags >> 1u) & 1u) != 0u;  // bit 1: outer angle format\n\n    return ClusterLightSpotData(\n        select(innerVal, 1.0 - innerVal, innerIsVersine),\n        select(outerVal, 1.0 - outerVal, outerIsVersine)\n    );\n}\n\nfn decodeClusterLightOmniAtlasViewport(lightIndex: i32) -> vec3f {\n    return sampleLightTextureF(lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_0}).xyz;\n}\n\nfn decodeClusterLightAreaData(lightIndex: i32) -> ClusterLightAreaData {\n    return ClusterLightAreaData(\n        sampleLightTextureF(lightIndex, {CLUSTER_TEXTURE_AREA_DATA_WIDTH}).xyz,\n        sampleLightTextureF(lightIndex, {CLUSTER_TEXTURE_AREA_DATA_HEIGHT}).xyz\n    );\n}\n\nfn decodeClusterLightProjectionMatrixData(lightIndex: i32) -> mat4x4f {\n    // shadow matrix\n    let m0: vec4f = sampleLightTextureF(lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_0});\n    let m1: vec4f = sampleLightTextureF(lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_1});\n    let m2: vec4f = sampleLightTextureF(lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_2});\n    let m3: vec4f = sampleLightTextureF(lightIndex, {CLUSTER_TEXTURE_PROJ_MAT_3});\n    return mat4x4f(m0, m1, m2, m3);\n}\n\nfn decodeClusterLightShadowData(biasesData: f32) -> ClusterLightShadowData {\n    // shadow biases\n    let biases: vec2f = unpack2x16float(bitcast<u32>(biasesData));\n    return ClusterLightShadowData(biases.x, biases.y);\n}\n\nfn decodeClusterLightCookieData() -> vec4f {\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    return step(vec4f(1.0), vec4f(mask_uvec)); // Normalize to 0.0 or 1.0\n}\n\nfn evaluateLight(\n    light: 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        let areaData: ClusterLightAreaData = decodeClusterLightAreaData(light.lightIndex);\n\n        // handle light shape\n        if (light.shape == {LIGHTSHAPE_RECT}) {\n            calcRectLightValues(light.position, areaData.halfWidth, areaData.halfHeight);\n        } else if (light.shape == {LIGHTSHAPE_DISK}) {\n            calcDiskLightValues(light.position, areaData.halfWidth, areaData.halfHeight);\n        } else { // sphere\n            calcSphereLightValues(light.position, areaData.halfWidth, areaData.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            let spotData: ClusterLightSpotData = decodeClusterLightSpot();\n            falloffAttenuation = falloffAttenuation * getSpotEffect(light.direction, spotData.innerConeAngleCos, spotData.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                var omniAtlasViewport: vec3f = vec3f(0.0);\n\n                // shared shadow / cookie data depends on light type\n                if (light.isSpot) {\n                    lightProjectionMatrix = decodeClusterLightProjectionMatrixData(light.lightIndex);\n                } else {\n                    omniAtlasViewport = decodeClusterLightOmniAtlasViewport(light.lightIndex);\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                    let cookieChannelMask: vec4f = decodeClusterLightCookieData();\n\n                    if (light.isSpot) {\n                        cookieAttenuation = getCookie2DClustered(cookieAtlasTexture, cookieAtlasTextureSampler, lightProjectionMatrix, vPositionW, light.cookieIntensity, cookieChannelMask);\n                    } else {\n                        cookieAttenuation = getCookieCubeClustered(cookieAtlasTexture, cookieAtlasTextureSampler, lightDirW, light.cookieIntensity, cookieChannelMask, shadowTextureResolution, shadowEdgePixels, omniAtlasViewport);\n                    }\n                }\n\n                #endif\n\n                #ifdef CLUSTER_SHADOWS\n\n                // shadow\n                if (light.shadowIntensity > 0.0) {\n                    let shadowData: ClusterLightShadowData = decodeClusterLightShadowData(light.biasesData);\n\n                    let shadowParams: vec4f = vec4f(shadowTextureResolution, shadowData.shadowNormalBias, shadowData.shadowBias, 1.0 / light.range);\n\n                    if (light.isSpot) {\n\n                        // spot shadow\n                        let shadowCoord: vec3f = getShadowCoordPerspZbufferNormalOffset(lightProjectionMatrix, shadowParams, geometricNormal);\n\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                        #if defined(CLUSTER_SHADOW_TYPE_PCF1)\n                            let shadow: f32 = getShadowOmniClusteredPCF1(shadowAtlasTexture, shadowAtlasTextureSampler, shadowParams, omniAtlasViewport, shadowEdgePixels, dir);\n                        #elif defined(CLUSTER_SHADOW_TYPE_PCF3)\n                            let shadow: f32 = getShadowOmniClusteredPCF3(shadowAtlasTexture, shadowAtlasTextureSampler, shadowParams, omniAtlasViewport, shadowEdgePixels, dir);\n                        #elif defined(CLUSTER_SHADOW_TYPE_PCF5)\n                            let shadow: f32 = getShadowOmniClusteredPCF5(shadowAtlasTexture, shadowAtlasTextureSampler, shadowParams, 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: i32,\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    let clusterLightData: ClusterLightData = decodeClusterLightCore(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 if no lights (index 0 is reserved for 'no light')\n    if (uniform.numClusteredLights <= 1) {\n        return;\n    }\n\n    // world space position to 3d integer cell cordinates in the cluster structure\n    let cellCoords: vec3i = vec3i(floor((vPositionW - uniform.clusterBoundsMin) * uniform.clusterCellsCountByBoundsSize));\n\n    // no lighting when cell coordinate is out of range\n    if (!(any(cellCoords < vec3i(0)) || any(cellCoords >= uniform.clusterCellsMax))) {\n\n        // cell index (mapping from 3d cell coordinates to linear memory)\n        let cellIndex: i32 = cellCoords.x * uniform.clusterCellsDot.x + cellCoords.y * uniform.clusterCellsDot.y + cellCoords.z * uniform.clusterCellsDot.z;\n\n        // convert cell index to uv coordinates\n        let clusterV: i32 = cellIndex / uniform.clusterTextureWidth;\n        let clusterU: i32 = cellIndex - clusterV * uniform.clusterTextureWidth;\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 lightIndex: u32 = textureLoad(clusterWorldTexture, vec2<i32>(clusterU + lightCellIndex, clusterV), 0).r;\n\n            if (lightIndex == 0u) {\n                break;\n            }\n\n            evaluateClusterLight(\n                i32(lightIndex),\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;
