{
  "__type__": "cc.EffectAsset",
  "_name": "pipeline/deferred-lighting",
  "_objFlags": 0,
  "_native": "",
  "techniques": [
    {
      "passes": [
        {
          "phase": "deferred-lighting",
          "program": "pipeline/deferred-lighting|lighting-vs|lighting-fs",
          "depthStencilState": {
            "depthFunc": 4,
            "depthTest": true,
            "depthWrite": false
          }
        }
      ]
    }
  ],
  "shaders": [
    {
      "blocks": [],
      "samplerTextures": [
        {
          "name": "depth_stencil",
          "type": 28,
          "count": 1,
          "defines": [],
          "stageFlags": 16,
          "binding": 3
        }
      ],
      "samplers": [],
      "textures": [],
      "buffers": [
        {
          "name": "b_ccLightsBuffer",
          "memoryAccess": 1,
          "defines": [
            "CC_ENABLE_CLUSTERED_LIGHT_CULLING"
          ],
          "stageFlags": 16,
          "binding": 4
        },
        {
          "name": "b_clusterLightIndicesBuffer",
          "memoryAccess": 1,
          "defines": [
            "CC_ENABLE_CLUSTERED_LIGHT_CULLING"
          ],
          "stageFlags": 16,
          "binding": 5
        },
        {
          "name": "b_clusterLightGridBuffer",
          "memoryAccess": 1,
          "defines": [
            "CC_ENABLE_CLUSTERED_LIGHT_CULLING"
          ],
          "stageFlags": 16,
          "binding": 6
        }
      ],
      "images": [],
      "subpassInputs": [
        {
          "name": "gbuffer_albedoMap",
          "count": 1,
          "defines": [
            "CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT"
          ],
          "stageFlags": 16,
          "binding": 0
        },
        {
          "name": "gbuffer_normalMap",
          "count": 1,
          "defines": [
            "CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT"
          ],
          "stageFlags": 16,
          "binding": 1
        },
        {
          "name": "gbuffer_emissiveMap",
          "count": 1,
          "defines": [
            "CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT"
          ],
          "stageFlags": 16,
          "binding": 2
        }
      ],
      "attributes": [
        {
          "name": "a_position",
          "defines": [],
          "format": 32,
          "location": 0
        },
        {
          "name": "a_normal",
          "defines": [],
          "format": 32,
          "location": 1
        },
        {
          "name": "a_texCoord",
          "defines": [],
          "format": 21,
          "location": 2
        },
        {
          "name": "a_tangent",
          "defines": [],
          "format": 44,
          "location": 3
        }
      ],
      "varyings": [
        {
          "name": "v_uv",
          "type": 14,
          "count": 1,
          "defines": [],
          "stageFlags": 17,
          "location": 0
        }
      ],
      "fragColors": [
        {
          "tags": [],
          "name": "fragColor",
          "typename": "vec4",
          "type": 16,
          "count": 1,
          "defines": [],
          "stageFlags": 16,
          "location": 0
        }
      ],
      "hash": 3788484086,
      "glsl4": {
        "vert": "\nprecision highp float;\nstruct StandardVertInput {\n  highp vec4 position;\n  vec3 normal;\n  vec4 tangent;\n};\nlayout(location = 0) in vec3 a_position;\nlayout(location = 1) in vec3 a_normal;\nlayout(location = 2) in vec2 a_texCoord;\nlayout(location = 3) in vec4 a_tangent;\nlayout(set = 0, binding = 0) uniform CCGlobal {\n  highp   vec4 cc_time;\n  mediump vec4 cc_screenSize;\n  mediump vec4 cc_nativeSize;\n};\nlayout(set = 0, binding = 1) uniform CCCamera {\n  highp   mat4 cc_matView;\n  highp   mat4 cc_matViewInv;\n  highp   mat4 cc_matProj;\n  highp   mat4 cc_matProjInv;\n  highp   mat4 cc_matViewProj;\n  highp   mat4 cc_matViewProjInv;\n  highp   vec4 cc_cameraPos;\n  mediump vec4 cc_screenScale;\n  mediump vec4 cc_exposure;\n  mediump vec4 cc_mainLitDir;\n  mediump vec4 cc_mainLitColor;\n  mediump vec4 cc_ambientSky;\n  mediump vec4 cc_ambientGround;\n  mediump vec4 cc_fogColor;\n  mediump vec4 cc_fogBase;\n  mediump vec4 cc_fogAdd;\n  mediump vec4 cc_nearFar;\n  mediump vec4 cc_viewPort;\n};\nlayout(location = 0) out vec2 v_uv;\nvoid main () {\n  vec4 position;\n    position = vec4(a_position, 1.0);\n  position.xy = cc_cameraPos.w == 0.0 ? vec2(position.xy.x, -position.xy.y) : position.xy;\n  gl_Position = vec4(position.x, position.y, 1.0, 1.0);\n  v_uv = a_texCoord;\n}",
        "frag": "\n  precision highp float;\n  layout(set = 0, binding = 0) uniform CCGlobal {\n    highp   vec4 cc_time;\n    mediump vec4 cc_screenSize;\n    mediump vec4 cc_nativeSize;\n  };\n  layout(set = 0, binding = 1) uniform CCCamera {\n    highp   mat4 cc_matView;\n    highp   mat4 cc_matViewInv;\n    highp   mat4 cc_matProj;\n    highp   mat4 cc_matProjInv;\n    highp   mat4 cc_matViewProj;\n    highp   mat4 cc_matViewProjInv;\n    highp   vec4 cc_cameraPos;\n    mediump vec4 cc_screenScale;\n    mediump vec4 cc_exposure;\n    mediump vec4 cc_mainLitDir;\n    mediump vec4 cc_mainLitColor;\n    mediump vec4 cc_ambientSky;\n    mediump vec4 cc_ambientGround;\n    mediump vec4 cc_fogColor;\n    mediump vec4 cc_fogBase;\n    mediump vec4 cc_fogAdd;\n    mediump vec4 cc_nearFar;\n    mediump vec4 cc_viewPort;\n  };\n  vec3 SRGBToLinear (vec3 gamma) {\n    return gamma * gamma;\n  }\n  layout(set = 0, binding = 2) uniform CCShadow {\n    highp mat4 cc_matLightPlaneProj;\n    highp mat4 cc_matLightView;\n    highp mat4 cc_matLightViewProj;\n    highp vec4 cc_shadowInvProjDepthInfo;\n    highp vec4 cc_shadowProjDepthInfo;\n    highp vec4 cc_shadowProjInfo;\n    mediump vec4 cc_shadowNFLSInfo;\n    mediump vec4 cc_shadowWHPBInfo;\n    mediump vec4 cc_shadowLPNNInfo;\n    lowp vec4 cc_shadowColor;\n    mediump vec4 cc_planarNDInfo;\n  };\n    highp float unpackHighpData (float mainPart, float modPart) {\n      highp float data = mainPart;\n      return data + modPart;\n    }\n    highp float unpackHighpData (float mainPart, float modPart, const float modValue) {\n      highp float data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec2 unpackHighpData (vec2 mainPart, vec2 modPart) {\n      highp vec2 data = mainPart;\n      return data + modPart;\n    }\n    highp vec2 unpackHighpData (vec2 mainPart, vec2 modPart, const float modValue) {\n      highp vec2 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec3 unpackHighpData (vec3 mainPart, vec3 modPart) {\n      highp vec3 data = mainPart;\n      return data + modPart;\n    }\n    highp vec3 unpackHighpData (vec3 mainPart, vec3 modPart, const float modValue) {\n      highp vec3 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec4 unpackHighpData (vec4 mainPart, vec4 modPart) {\n      highp vec4 data = mainPart;\n      return data + modPart;\n    }\n    highp vec4 unpackHighpData (vec4 mainPart, vec4 modPart, const float modValue) {\n      highp vec4 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n  float CCGetLinearDepthFromViewSpace(vec3 viewPos) {\n    float dist = length(viewPos);\n    return (dist - cc_shadowNFLSInfo.x) / (cc_shadowNFLSInfo.y - cc_shadowNFLSInfo.x);\n  }\n  float CCGetLinearDepth(vec3 worldPos) {\n    vec4 viewStartPos = cc_matLightView * vec4(worldPos.xyz, 1.0);\n    return CCGetLinearDepthFromViewSpace(viewStartPos.xyz);\n  }\n  #if CC_RECEIVE_SHADOW\n    layout(set = 0, binding = 3) uniform highp sampler2D cc_shadowMap;\n    layout(set = 0, binding = 5) uniform highp sampler2D cc_spotLightingMap;\n    vec4 ApplyShadowDepthBias_FaceNormal(vec4 shadowPos, vec3 worldNormal)\n    {\n      vec4 newShadowPos = shadowPos;\n      if(cc_shadowLPNNInfo.z > 0.0001)\n      {\n        vec4 viewNormal = cc_matLightView * vec4(worldNormal, 0.0);\n        if(viewNormal.z < 0.1)\n          newShadowPos.xy += viewNormal.xy * cc_shadowProjInfo.xy * cc_shadowLPNNInfo.z * clamp(viewNormal.z, 0.001, 0.1);\n      }\n      return newShadowPos;\n    }\n    vec4 ApplyShadowDepthBias_Perspective(vec4 shadowPos, float viewspaceDepthBias)\n    {\n      vec3 viewSpacePos;\n      viewSpacePos.xy = shadowPos.xy * cc_shadowProjInfo.zw;\n      viewSpacePos.z = shadowPos.z * cc_shadowInvProjDepthInfo.x + shadowPos.w * cc_shadowInvProjDepthInfo.y;\n      viewSpacePos.xyz += cc_shadowProjDepthInfo.z * normalize(viewSpacePos.xyz) * viewspaceDepthBias;\n      vec4 clipSpacePos;\n      clipSpacePos.xy = viewSpacePos.xy * cc_shadowProjInfo.xy;\n      clipSpacePos.zw = viewSpacePos.z * cc_shadowProjDepthInfo.xz + vec2(cc_shadowProjDepthInfo.y, 0.0);\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        clipSpacePos.z = CCGetLinearDepthFromViewSpace(viewSpacePos.xyz);\n        clipSpacePos.z = (clipSpacePos.z * 2.0 - 1.0) * clipSpacePos.w;\n      }\n      return clipSpacePos;\n    }\n    vec4 ApplyShadowDepthBias_Orthographic(vec4 shadowPos, float viewspaceDepthBias)\n    {\n      float coeffA = cc_shadowProjDepthInfo.x;\n      float coeffB = cc_shadowProjDepthInfo.y;\n      float viewSpacePos_z = (shadowPos.z - coeffB) / coeffA;\n      viewSpacePos_z += viewspaceDepthBias;\n      vec4 result = shadowPos;\n      result.z = viewSpacePos_z * coeffA + coeffB;\n      return result;\n    }\n    float CCGetShadowFactorHard (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float shadow = 0.0;\n      float closestDepth = 0.0;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        closestDepth = dot(texture(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));\n      } else {\n        closestDepth = texture(cc_shadowMap, clipPos.xy).x;\n      }\n      shadow = step(clipPos.z, closestDepth);\n      return shadow;\n    }\n    float CCGetShadowFactorSoft (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float offsetDepth = clipPos.z;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      vec2 clipPos_offset = clipPos.xy + oneTap;\n      float block0, block1, block2, block3;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)).x);\n        block1 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset.x, clipPos.y)).x);\n        block2 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset.y)).x);\n        block3 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset.x, clipPos_offset.y)).x);\n      }\n      float coefX   = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block2, block3, coefX);\n      float coefY   = mod(clipPos.y, oneTap.y) * mapSize.y;\n      return mix(resultX, resultY, coefY);\n    }\n    float CCGetShadowFactorSoft2X (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float offsetDepth = clipPos.z;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      float clipPos_offset_L = clipPos.x - oneTap.x;\n      float clipPos_offset_R = clipPos.x + oneTap.x;\n      float clipPos_offset_U = clipPos.y - oneTap.y;\n      float clipPos_offset_D = clipPos.y + oneTap.y;\n      float block0, block1, block2, block3, block4, block5, block6, block7, block8;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block4 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block5 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block6 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block7 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block8 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_U)).x);\n        block1 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset_U)).x);\n        block2 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_U)).x);\n        block3 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos.y)).x);\n        block4 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)).x);\n        block5 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos.y)).x);\n        block6 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_D)).x);\n        block7 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset_D)).x);\n        block8 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_D)).x);\n      }\n      float coefX = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float coefY = mod(clipPos.y, oneTap.y) * mapSize.y;\n      float shadow = 0.0;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block3, block4, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block1, block2, coefX);\n      resultY = mix(block4, block5, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block3, block4, coefX);\n      resultY = mix(block6, block7, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      resultX = mix(block4, block5, coefX);\n      resultY = mix(block7, block8, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      return shadow * 0.25;\n    }\n    float CCGetSpotLightShadowFactorHard (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float shadow = 0.0;\n      float closestDepth = 0.0;\n      float depth = clipPos.z;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        closestDepth = dot(texture(cc_spotLightingMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));\n      } else {\n        closestDepth = texture(cc_spotLightingMap, clipPos.xy).x;\n      }\n      shadow = step(depth, closestDepth);\n      return shadow;\n    }\n    float CCGetSpotLightShadowFactorSoft (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float depth = 0.0;\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        depth = CCGetLinearDepth(worldPos);\n      } else {\n        depth = clipPos.z;\n      }\n      float bias = cc_shadowWHPBInfo.w;\n      vec2 oneTap = 1.0 / cc_shadowWHPBInfo.xy;\n      vec2 clipPos_offset = clipPos.xy + oneTap;\n      float block0, block1, block2, block3;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)).x);\n        block1 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos.y)).x);\n        block2 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset.y)).x);\n        block3 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos_offset.y)).x);\n      }\n      float coefX   = mod(clipPos.x, oneTap.x) * cc_shadowWHPBInfo.x;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block2, block3, coefX);\n      float coefY   = mod(clipPos.y, oneTap.y) * cc_shadowWHPBInfo.y;\n      return mix(resultX, resultY, coefY);\n    }\n    float CCGetSpotLightShadowFactorSoft2X (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float depth = 0.0;\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        depth = CCGetLinearDepth(worldPos);\n      } else {\n        depth = clipPos.z;\n      }\n      float bias = cc_shadowWHPBInfo.w;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      float clipPos_offset_L = clipPos.x - oneTap.x;\n      float clipPos_offset_R = clipPos.x + oneTap.x;\n      float clipPos_offset_U = clipPos.y - oneTap.y;\n      float clipPos_offset_D = clipPos.y + oneTap.y;\n      float block0, block1, block2, block3, block4, block5, block6, block7, block8;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block4 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block5 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block6 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block7 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block8 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_U)).x);\n        block1 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_U)).x);\n        block2 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_U)).x);\n        block3 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos.y)).x);\n        block4 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)).x);\n        block5 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos.y)).x);\n        block6 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_D)).x);\n        block7 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_D)).x);\n        block8 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_D)).x);\n      }\n      float coefX = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float coefY = mod(clipPos.y, oneTap.y) * mapSize.y;\n      float shadow = 0.0;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block3, block4, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block1, block2, coefX);\n      resultY = mix(block4, block5, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block3, block4, coefX);\n      resultY = mix(block6, block7, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      resultX = mix(block4, block5, coefX);\n      resultY = mix(block7, block8, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      return shadow * 0.25;\n    }\n  #endif\n  #if CC_USE_IBL\n    layout(set = 0, binding = 4) uniform samplerCube cc_environment;\n    vec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n        return textureLod(tex, coord, lod);\n    }\n    vec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n        return textureLod(tex, coord, lod);\n    }\n    vec3 unpackRGBE (vec4 rgbe) {\n      return rgbe.rgb * pow(1.1, rgbe.a * 255.0 - 128.0);\n    }\n    #if CC_USE_DIFFUSEMAP\n      layout(set = 0, binding = 6) uniform samplerCube cc_diffuseMap;\n    #endif\n  #endif\n  float GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n    vec3 NxH = cross(N, H);\n    float OneMinusNoHSqr = dot(NxH, NxH);\n    float a = roughness * roughness;\n    float n = NoH * a;\n    float p = a / (OneMinusNoHSqr + n * n);\n    return p * p;\n  }\n  float CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n    return (roughness * 0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n  }\n  vec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n    const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n    const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n    vec4 r = roughness * c0 + c1;\n    float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;\n    vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;\n    AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n    return specular * AB.x + AB.y;\n  }\n  #if USE_REFLECTION_DENOISE\n    vec3 GetEnvReflectionWithMipFiltering(vec3 R, float roughness, float mipCount, float denoiseIntensity) {\n      #if CC_USE_IBL\n      \tfloat mip = roughness * mipCount;\n      \tfloat delta = (dot(dFdx(R), dFdy(R))) * 1000.0;\n      \tfloat mipBias = mix(0.0, 5.0, clamp(delta, 0.0, 1.0));\n      \tvec4 biased = fragTextureLod(cc_environment, R, mip + mipBias);\n       \tvec4 filtered = texture(cc_environment, R);\n        #if CC_USE_IBL == 2\n        \tbiased.rgb = unpackRGBE(biased);\n        \tfiltered.rgb = unpackRGBE(filtered);\n        #else\n        \tbiased.rgb = SRGBToLinear(biased.rgb);\n        \tfiltered.rgb = SRGBToLinear(filtered.rgb);\n        #endif\n        return mix(biased.rgb, filtered.rgb, denoiseIntensity);\n      #else\n        return vec3(0.0, 0.0, 0.0);\n      #endif\n    }\n  #endif\n  struct StandardSurface {\n    vec4 albedo;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      vec3 position, position_fract_part;\n      #else\n      vec3 position;\n      #endif\n    vec3 normal;\n    vec3 emissive;\n    vec3 lightmap;\n    float lightmap_test;\n    float roughness;\n    float metallic;\n    float occlusion;\n  };\n  vec4 CCStandardShadingBase (StandardSurface s, vec4 shadowPos) {\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.0);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 L = normalize(-cc_mainLitDir.xyz);\n    vec3 H = normalize(L + V);\n    float NH = max(dot(N, H), 0.0);\n    float NL = max(dot(N, L), 0.0);\n    vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n    vec3 diffuseContrib = diffuse;\n    #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n      if (s.lightmap_test > 0.0001) {\n        finalColor = s.lightmap.rgb;\n      }\n    #else\n      diffuseContrib /= 3.14159265359;\n    #endif\n    vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n    vec3 dirlightContrib = (diffuseContrib + specularContrib);\n    float shadow = 1.0;\n    #if CC_RECEIVE_SHADOW\n      if (NL > 0.0 && cc_mainLitDir.w > 0.0) {\n          {\n            vec4 pos = ApplyShadowDepthBias_FaceNormal(shadowPos, N);\n            float pcf = cc_shadowWHPBInfo.z;\n            if (pcf > 1.9) shadow = CCGetShadowFactorSoft2X(pos);\n            else if (pcf > 0.9) shadow = CCGetShadowFactorSoft(pos);\n            else shadow = CCGetShadowFactorHard(pos);\n            shadow = mix(shadow, 1.0, cc_shadowNFLSInfo.w);\n          }\n      }\n    #endif\n    dirlightContrib *= shadow;\n    finalColor *= dirlightContrib;\n    float fAmb = 0.5 - N.y * 0.5;\n    vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb);\n    #if CC_USE_IBL\n      #if CC_USE_DIFFUSEMAP\n        vec4 diffuseMap = texture(cc_diffuseMap, N);\n        #if CC_USE_DIFFUSEMAP == 2\n          ambDiff = unpackRGBE(diffuseMap);\n        #else\n          ambDiff = SRGBToLinear(diffuseMap.rgb);\n        #endif\n      #endif\n      vec3 R = normalize(reflect(-V, N));\n      #if USE_REFLECTION_DENOISE\n        vec3 env = GetEnvReflectionWithMipFiltering(R, s.roughness, cc_ambientGround.w, 0.6);\n      #else\n        vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n        #if CC_USE_IBL == 2\n          vec3 env = unpackRGBE(envmap);\n        #else\n          vec3 env = SRGBToLinear(envmap.rgb);\n        #endif\n      #endif\n      finalColor += env * cc_ambientSky.w * specular * s.occlusion;\n    #endif\n    finalColor += ambDiff.rgb * cc_ambientSky.w * diffuse * s.occlusion;\n    finalColor += s.emissive;\n    return vec4(finalColor, s.albedo.a);\n  }\n  #if CC_PIPELINE_TYPE == 0\n  # define LIGHTS_PER_PASS 1\n  #else\n  # define LIGHTS_PER_PASS 10\n  #endif\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 0\n  layout(set = 2, binding = 1) uniform CCForwardLight {\n    highp vec4 cc_lightPos[LIGHTS_PER_PASS];\n    vec4 cc_lightColor[LIGHTS_PER_PASS];\n    vec4 cc_lightSizeRangeAngle[LIGHTS_PER_PASS];\n    vec4 cc_lightDir[LIGHTS_PER_PASS];\n  };\n  #endif\n  float SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n    float factor = distSqr * invSqrAttRadius;\n    float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n    return smoothFactor * smoothFactor;\n  }\n  float GetDistAtt (float distSqr, float invSqrAttRadius) {\n    float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n    attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n    return attenuation;\n  }\n  float GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n    float cd = dot(litDir, L);\n    float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n    return (attenuation * attenuation);\n  }\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 0\n  vec4 CCStandardShadingAdditive (StandardSurface s, vec4 shadowPos) {\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 diffuseContrib = diffuse / 3.14159265359;\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.0);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 finalColor = vec3(0.0);\n    int numLights = CC_PIPELINE_TYPE == 0 ? LIGHTS_PER_PASS : int(cc_lightDir[0].w);\n    for (int i = 0; i < LIGHTS_PER_PASS; i++) {\n      if (i >= numLights) break;\n      vec3 SLU = cc_lightPos[i].xyz - position;\n      vec3 SL = normalize(SLU);\n      vec3 SH = normalize(SL + V);\n      float SNL = max(dot(N, SL), 0.0);\n      float SNH = max(dot(N, SH), 0.0);\n      float distSqr = dot(SLU, SLU);\n      float litRadius = cc_lightSizeRangeAngle[i].x;\n      float litRadiusSqr = litRadius * litRadius;\n      float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n      float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n      attRadiusSqrInv *= attRadiusSqrInv;\n      float att = GetDistAtt(distSqr, attRadiusSqrInv);\n      vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n      if (cc_lightPos[i].w > 0.0) {\n        float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n        float cosOuter = cc_lightSizeRangeAngle[i].z;\n        float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n        float litAngleOffset = -cosOuter * litAngleScale;\n        att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n      }\n      vec3 lightColor = cc_lightColor[i].rgb;\n      float shadow = 1.0;\n      #if CC_RECEIVE_SHADOW\n        if (cc_lightPos[i].w > 0.0 && cc_lightSizeRangeAngle[i].w > 0.0) {\n            {\n              float pcf = cc_shadowWHPBInfo.z;\n              if (pcf > 1.9) shadow = CCGetSpotLightShadowFactorSoft2X(shadowPos, position);\n              else if (pcf > 0.9) shadow = CCGetSpotLightShadowFactorSoft(shadowPos, position);\n              else shadow = CCGetSpotLightShadowFactorHard(shadowPos, position);\n            }\n        }\n      #endif\n      lightColor *= shadow;\n      finalColor += SNL * lightColor * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n    }\n    return vec4(finalColor, 0.0);\n  }\n  #endif\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 1\n  layout(set = 1, binding = 4) readonly buffer b_ccLightsBuffer { vec4 b_ccLights[]; };\n  layout(set = 1, binding = 5) readonly buffer b_clusterLightIndicesBuffer { uint b_clusterLightIndices[]; };\n  layout(set = 1, binding = 6) readonly buffer b_clusterLightGridBuffer { uvec4 b_clusterLightGrid[]; };\n  struct CCLight\n  {\n    vec4 cc_lightPos;\n    vec4 cc_lightColor;\n    vec4 cc_lightSizeRangeAngle;\n    vec4 cc_lightDir;\n  };\n  struct Cluster\n  {\n    vec3 minBounds;\n    vec3 maxBounds;\n  };\n  struct LightGrid\n  {\n    uint offset;\n    uint ccLights;\n  };\n  CCLight getCCLight(uint i)\n  {\n    CCLight light;\n    light.cc_lightPos = b_ccLights[4u * i + 0u];\n    light.cc_lightColor = b_ccLights[4u * i + 1u];\n    light.cc_lightSizeRangeAngle = b_ccLights[4u * i + 2u];\n    light.cc_lightDir = b_ccLights[4u * i + 3u];\n    return light;\n  }\n  LightGrid getLightGrid(uint cluster)\n  {\n    uvec4 gridvec = b_clusterLightGrid[cluster];\n    LightGrid grid;\n    grid.offset = gridvec.x;\n    grid.ccLights = gridvec.y;\n    return grid;\n  }\n  uint getGridLightIndex(uint start, uint offset)\n  {\n    return b_clusterLightIndices[start + offset];\n  }\n  uint getClusterZIndex(vec4 worldPos)\n  {\n    float scale = float(24) / log(cc_nearFar.y / cc_nearFar.x);\n    float bias = -(float(24) * log(cc_nearFar.x) / log(cc_nearFar.y / cc_nearFar.x));\n    float eyeDepth = -(cc_matView * worldPos).z;\n    uint zIndex = uint(max(log(eyeDepth) * scale + bias, 0.0));\n    return zIndex;\n  }\n  uint getClusterIndex(vec4 fragCoord, vec4 worldPos)\n  {\n    uint zIndex = getClusterZIndex(worldPos);\n    float clusterSizeX = ceil(cc_viewPort.z / float(16));\n    float clusterSizeY = ceil(cc_viewPort.w / float(8));\n    uvec3 indices = uvec3(uvec2(fragCoord.xy / vec2(clusterSizeX, clusterSizeY)), zIndex);\n    uint cluster = (16u * 8u) * indices.z + 16u * indices.y + indices.x;\n    return cluster;\n  }\n  vec4 CCClusterShadingAdditive (StandardSurface s, vec4 shadowPos) {\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 diffuseContrib = diffuse / 3.14159265359;\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.001);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 finalColor = vec3(0.0);\n    uint cluster = getClusterIndex(gl_FragCoord, vec4(position, 1.0));\n    LightGrid grid = getLightGrid(cluster);\n    uint numLights = grid.ccLights;\n    for (uint i = 0u; i < 100u; i++) {\n      if (i >= numLights) break;\n      uint lightIndex = getGridLightIndex(grid.offset, i);\n      CCLight light = getCCLight(lightIndex);\n      vec3 SLU = light.cc_lightPos.xyz - position;\n      vec3 SL = normalize(SLU);\n      vec3 SH = normalize(SL + V);\n      float SNL = max(dot(N, SL), 0.001);\n      float SNH = max(dot(N, SH), 0.0);\n      float distSqr = dot(SLU, SLU);\n      float litRadius = light.cc_lightSizeRangeAngle.x;\n      float litRadiusSqr = litRadius * litRadius;\n      float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n      float attRadiusSqrInv = 1.0 / max(light.cc_lightSizeRangeAngle.y, 0.01);\n      attRadiusSqrInv *= attRadiusSqrInv;\n      float att = GetDistAtt(distSqr, attRadiusSqrInv);\n      vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n      if (light.cc_lightPos.w > 0.0) {\n        float cosInner = max(dot(-light.cc_lightDir.xyz, SL), 0.01);\n        float cosOuter = light.cc_lightSizeRangeAngle.z;\n        float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n        float litAngleOffset = -cosOuter * litAngleScale;\n        att *= GetAngleAtt(SL, -light.cc_lightDir.xyz, litAngleScale, litAngleOffset);\n      }\n      vec3 lightColor = light.cc_lightColor.rgb;\n      float shadow = 1.0;\n      #if CC_RECEIVE_SHADOW\n        if (light.cc_lightPos.w > 0.0) {\n            {\n              float pcf = cc_shadowWHPBInfo.z;\n              if (pcf > 1.9) shadow = CCGetSpotLightShadowFactorSoft2X(shadowPos, position);\n              else if (pcf > 0.9) shadow = CCGetSpotLightShadowFactorSoft(shadowPos, position);\n              else shadow = CCGetSpotLightShadowFactorHard(shadowPos, position);\n            }\n        }\n      #endif\n      lightColor *= shadow;\n      finalColor += SNL * lightColor * light.cc_lightColor.w * illum * att * (diffuseContrib + lspec);\n    }\n    return vec4(finalColor, 0.0);\n  }\n  #endif\n  vec3 ACESToneMap (vec3 color) {\n    color = min(color, vec3(8.0));\n    const float A = 2.51;\n    const float B = 0.03;\n    const float C = 2.43;\n    const float D = 0.59;\n    const float E = 0.14;\n    return (color * (A * color + B)) / (color * (C * color + D) + E);\n  }\n  vec4 CCFragOutput (vec4 color) {\n    #if CC_USE_HDR\n      color.rgb = ACESToneMap(color.rgb);\n    #endif\n    color.rgb = sqrt(color.rgb);\n    return color;\n  }\n  float LinearFog(vec4 pos) {\n    vec4 wPos = pos;\n    float cam_dis = distance(cc_cameraPos, wPos);\n    float fogStart = cc_fogBase.x;\n    float fogEnd = cc_fogBase.y;\n    return clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);\n  }\n  float ExpFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float fogStart = cc_fogBase.x;\n    float fogDensity = cc_fogBase.z;\n    float cam_dis = max(distance(cc_cameraPos, wPos) - fogStart, 0.0) / fogAtten * 4.;\n    float f = exp(-cam_dis * fogDensity);\n    return f;\n  }\n  float ExpSquaredFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float fogStart = cc_fogBase.x;\n    float fogDensity = cc_fogBase.z;\n    float cam_dis = max(distance(cc_cameraPos, wPos) - fogStart, 0.0) / fogAtten * 4.;\n    float f = exp(-cam_dis * cam_dis * fogDensity * fogDensity);\n    return f;\n  }\n  float LayeredFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float _FogTop = cc_fogAdd.x;\n    float _FogRange = cc_fogAdd.y;\n    vec3 camWorldProj = cc_cameraPos.xyz;\n    camWorldProj.y = 0.;\n    vec3 worldPosProj = wPos.xyz;\n    worldPosProj.y = 0.;\n    float fDeltaD = distance(worldPosProj, camWorldProj) / fogAtten * 2.0;\n    float fDeltaY, fDensityIntegral;\n    if (cc_cameraPos.y > _FogTop) {\n      if (wPos.y < _FogTop) {\n        fDeltaY = (_FogTop - wPos.y) / _FogRange * 2.0;\n        fDensityIntegral = fDeltaY * fDeltaY * 0.5;\n      } else {\n        fDeltaY = 0.;\n        fDensityIntegral = 0.;\n      }\n    } else {\n      if (wPos.y < _FogTop) {\n        float fDeltaA = (_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n        float fDeltaB = (_FogTop - wPos.y) / _FogRange * 2.;\n        fDeltaY = abs(fDeltaA - fDeltaB);\n        fDensityIntegral = abs((fDeltaA * fDeltaA * 0.5) - (fDeltaB * fDeltaB * 0.5));\n      } else {\n        fDeltaY = abs(_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n        fDensityIntegral = abs(fDeltaY * fDeltaY * 0.5);\n      }\n    }\n    float fDensity;\n    if (fDeltaY != 0.) {\n      fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;\n    } else {\n      fDensity = 0.;\n    }\n    float f = exp(-fDensity);\n    return f;\n  }\n  void CC_TRANSFER_FOG_BASE(vec4 pos, out float factor)\n  {\n    #if CC_USE_FOG == 0\n  \tfactor = LinearFog(pos);\n    #elif CC_USE_FOG == 1\n      factor = ExpFog(pos);\n    #elif CC_USE_FOG == 2\n      factor = ExpSquaredFog(pos);\n    #elif CC_USE_FOG == 3\n      factor = LayeredFog(pos);\n    #else\n      factor = 1.0;\n    #endif\n  }\n  void CC_APPLY_FOG_BASE(inout vec4 color, float factor) {\n    color = vec4(mix(cc_fogColor.rgb, color.rgb, factor), color.a);\n  }\n  vec2 signNotZero(vec2 v) {\n    return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);\n  }\n  vec3 oct_to_float32x3(vec2 e) {\n    vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));\n    if (v.z < 0.0) v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);\n    return normalize(v);\n  }\n  vec4 screen2WS(vec3 coord) {\n    vec3 ndc = vec3(\n  \t  2.0 * (coord.x - cc_viewPort.x) / cc_viewPort.z - 1.0,\n      2.0 * (coord.y - cc_viewPort.y) / cc_viewPort.w - 1.0,\n      coord.z);\n    vec4 world = ((cc_matViewProjInv) * (vec4(ndc, 1.0)));\n    world      = world / world.w;\n    return world;\n  }\n  layout(location = 0) in vec2 v_uv;\n  #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n      layout(set = 1, binding = 0, input_attachment_index = 0) uniform subpassInput gbuffer_albedoMap;\n      layout(set = 1, binding = 1, input_attachment_index = 1) uniform subpassInput gbuffer_normalMap;\n      layout(set = 1, binding = 2, input_attachment_index = 2) uniform subpassInput gbuffer_emissiveMap;\n  #else\n    layout(set = 1, binding = 0) uniform sampler2D gbuffer_albedoMap;\n    layout(set = 1, binding = 1) uniform sampler2D gbuffer_normalMap;\n    layout(set = 1, binding = 2) uniform sampler2D gbuffer_emissiveMap;\n  #endif\n  layout(set = 1, binding = 3) uniform sampler2D depth_stencil;\n  #if !CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT || __VERSION__ >= 450\n    layout(location = 0) out vec4 fragColor;\n  #endif\n  void main () {\n    StandardSurface s;\n    #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n        vec4 albedoMap = subpassLoad(gbuffer_albedoMap);\n        vec4 normalMap = subpassLoad(gbuffer_normalMap);\n        vec4 emissiveMap = subpassLoad(gbuffer_emissiveMap);\n    #else\n      vec4 albedoMap = texture(gbuffer_albedoMap,v_uv);\n      vec4 normalMap = texture(gbuffer_normalMap,v_uv);\n      vec4 emissiveMap = texture(gbuffer_emissiveMap,v_uv);\n    #endif\n    float depth = texture(depth_stencil, v_uv).x;\n    s.albedo = albedoMap;\n    vec3 position = screen2WS(vec3(gl_FragCoord.xy, depth)).xyz;\n    s.position = position;\n    s.roughness = normalMap.z;\n    s.normal = oct_to_float32x3(normalMap.xy);\n    s.metallic = normalMap.w;\n    s.emissive = emissiveMap.xyz;\n    s.occlusion = emissiveMap.w;\n    float fogFactor;\n    CC_TRANSFER_FOG_BASE(vec4(position, 1), fogFactor);\n    vec4 shadowPos;\n      shadowPos = cc_matLightViewProj * vec4(position, 1);\n    vec4 color = CCStandardShadingBase(s, shadowPos) +\n#if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 1\n                 CCClusterShadingAdditive(s, shadowPos);\n#else\n                 CCStandardShadingAdditive(s, shadowPos);\n#endif\n    CC_APPLY_FOG_BASE(color, fogFactor);\n    color = CCFragOutput(color);\n    #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n        fragColor = color;\n    #else\n      fragColor = color;\n    #endif\n  }"
      },
      "glsl3": {
        "vert": "\nprecision highp float;\nstruct StandardVertInput {\n  highp vec4 position;\n  vec3 normal;\n  vec4 tangent;\n};\nin vec3 a_position;\nin vec3 a_normal;\nin vec2 a_texCoord;\nin vec4 a_tangent;\nlayout(std140) uniform CCGlobal {\n  highp   vec4 cc_time;\n  mediump vec4 cc_screenSize;\n  mediump vec4 cc_nativeSize;\n};\nlayout(std140) uniform CCCamera {\n  highp   mat4 cc_matView;\n  highp   mat4 cc_matViewInv;\n  highp   mat4 cc_matProj;\n  highp   mat4 cc_matProjInv;\n  highp   mat4 cc_matViewProj;\n  highp   mat4 cc_matViewProjInv;\n  highp   vec4 cc_cameraPos;\n  mediump vec4 cc_screenScale;\n  mediump vec4 cc_exposure;\n  mediump vec4 cc_mainLitDir;\n  mediump vec4 cc_mainLitColor;\n  mediump vec4 cc_ambientSky;\n  mediump vec4 cc_ambientGround;\n  mediump vec4 cc_fogColor;\n  mediump vec4 cc_fogBase;\n  mediump vec4 cc_fogAdd;\n  mediump vec4 cc_nearFar;\n  mediump vec4 cc_viewPort;\n};\nout vec2 v_uv;\nvoid main () {\n  vec4 position;\n    position = vec4(a_position, 1.0);\n  position.xy = cc_cameraPos.w == 0.0 ? vec2(position.xy.x, -position.xy.y) : position.xy;\n  gl_Position = vec4(position.x, position.y, 1.0, 1.0);\n  v_uv = a_texCoord;\n}",
        "frag": "\n#ifdef GL_EXT_shader_framebuffer_fetch\n#extension GL_EXT_shader_framebuffer_fetch: enable\n#endif\n  precision highp float;\n  layout(std140) uniform CCGlobal {\n    highp   vec4 cc_time;\n    mediump vec4 cc_screenSize;\n    mediump vec4 cc_nativeSize;\n  };\n  layout(std140) uniform CCCamera {\n    highp   mat4 cc_matView;\n    highp   mat4 cc_matViewInv;\n    highp   mat4 cc_matProj;\n    highp   mat4 cc_matProjInv;\n    highp   mat4 cc_matViewProj;\n    highp   mat4 cc_matViewProjInv;\n    highp   vec4 cc_cameraPos;\n    mediump vec4 cc_screenScale;\n    mediump vec4 cc_exposure;\n    mediump vec4 cc_mainLitDir;\n    mediump vec4 cc_mainLitColor;\n    mediump vec4 cc_ambientSky;\n    mediump vec4 cc_ambientGround;\n    mediump vec4 cc_fogColor;\n    mediump vec4 cc_fogBase;\n    mediump vec4 cc_fogAdd;\n    mediump vec4 cc_nearFar;\n    mediump vec4 cc_viewPort;\n  };\n  vec3 SRGBToLinear (vec3 gamma) {\n    return gamma * gamma;\n  }\n  layout(std140) uniform CCShadow {\n    highp mat4 cc_matLightPlaneProj;\n    highp mat4 cc_matLightView;\n    highp mat4 cc_matLightViewProj;\n    highp vec4 cc_shadowInvProjDepthInfo;\n    highp vec4 cc_shadowProjDepthInfo;\n    highp vec4 cc_shadowProjInfo;\n    mediump vec4 cc_shadowNFLSInfo;\n    mediump vec4 cc_shadowWHPBInfo;\n    mediump vec4 cc_shadowLPNNInfo;\n    lowp vec4 cc_shadowColor;\n    mediump vec4 cc_planarNDInfo;\n  };\n    highp float unpackHighpData (float mainPart, float modPart) {\n      highp float data = mainPart;\n      return data + modPart;\n    }\n    highp float unpackHighpData (float mainPart, float modPart, const float modValue) {\n      highp float data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec2 unpackHighpData (vec2 mainPart, vec2 modPart) {\n      highp vec2 data = mainPart;\n      return data + modPart;\n    }\n    highp vec2 unpackHighpData (vec2 mainPart, vec2 modPart, const float modValue) {\n      highp vec2 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec3 unpackHighpData (vec3 mainPart, vec3 modPart) {\n      highp vec3 data = mainPart;\n      return data + modPart;\n    }\n    highp vec3 unpackHighpData (vec3 mainPart, vec3 modPart, const float modValue) {\n      highp vec3 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec4 unpackHighpData (vec4 mainPart, vec4 modPart) {\n      highp vec4 data = mainPart;\n      return data + modPart;\n    }\n    highp vec4 unpackHighpData (vec4 mainPart, vec4 modPart, const float modValue) {\n      highp vec4 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n  float CCGetLinearDepthFromViewSpace(vec3 viewPos) {\n    float dist = length(viewPos);\n    return (dist - cc_shadowNFLSInfo.x) / (cc_shadowNFLSInfo.y - cc_shadowNFLSInfo.x);\n  }\n  float CCGetLinearDepth(vec3 worldPos) {\n    vec4 viewStartPos = cc_matLightView * vec4(worldPos.xyz, 1.0);\n    return CCGetLinearDepthFromViewSpace(viewStartPos.xyz);\n  }\n  #if CC_RECEIVE_SHADOW\n    uniform highp sampler2D cc_shadowMap;\n    uniform highp sampler2D cc_spotLightingMap;\n    vec4 ApplyShadowDepthBias_FaceNormal(vec4 shadowPos, vec3 worldNormal)\n    {\n      vec4 newShadowPos = shadowPos;\n      if(cc_shadowLPNNInfo.z > 0.0001)\n      {\n        vec4 viewNormal = cc_matLightView * vec4(worldNormal, 0.0);\n        if(viewNormal.z < 0.1)\n          newShadowPos.xy += viewNormal.xy * cc_shadowProjInfo.xy * cc_shadowLPNNInfo.z * clamp(viewNormal.z, 0.001, 0.1);\n      }\n      return newShadowPos;\n    }\n    vec4 ApplyShadowDepthBias_Perspective(vec4 shadowPos, float viewspaceDepthBias)\n    {\n      vec3 viewSpacePos;\n      viewSpacePos.xy = shadowPos.xy * cc_shadowProjInfo.zw;\n      viewSpacePos.z = shadowPos.z * cc_shadowInvProjDepthInfo.x + shadowPos.w * cc_shadowInvProjDepthInfo.y;\n      viewSpacePos.xyz += cc_shadowProjDepthInfo.z * normalize(viewSpacePos.xyz) * viewspaceDepthBias;\n      vec4 clipSpacePos;\n      clipSpacePos.xy = viewSpacePos.xy * cc_shadowProjInfo.xy;\n      clipSpacePos.zw = viewSpacePos.z * cc_shadowProjDepthInfo.xz + vec2(cc_shadowProjDepthInfo.y, 0.0);\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        clipSpacePos.z = CCGetLinearDepthFromViewSpace(viewSpacePos.xyz);\n        clipSpacePos.z = (clipSpacePos.z * 2.0 - 1.0) * clipSpacePos.w;\n      }\n      return clipSpacePos;\n    }\n    vec4 ApplyShadowDepthBias_Orthographic(vec4 shadowPos, float viewspaceDepthBias)\n    {\n      float coeffA = cc_shadowProjDepthInfo.x;\n      float coeffB = cc_shadowProjDepthInfo.y;\n      float viewSpacePos_z = (shadowPos.z - coeffB) / coeffA;\n      viewSpacePos_z += viewspaceDepthBias;\n      vec4 result = shadowPos;\n      result.z = viewSpacePos_z * coeffA + coeffB;\n      return result;\n    }\n    float CCGetShadowFactorHard (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float shadow = 0.0;\n      float closestDepth = 0.0;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        closestDepth = dot(texture(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));\n      } else {\n        closestDepth = texture(cc_shadowMap, clipPos.xy).x;\n      }\n      shadow = step(clipPos.z, closestDepth);\n      return shadow;\n    }\n    float CCGetShadowFactorSoft (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float offsetDepth = clipPos.z;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      vec2 clipPos_offset = clipPos.xy + oneTap;\n      float block0, block1, block2, block3;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)).x);\n        block1 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset.x, clipPos.y)).x);\n        block2 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset.y)).x);\n        block3 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset.x, clipPos_offset.y)).x);\n      }\n      float coefX   = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block2, block3, coefX);\n      float coefY   = mod(clipPos.y, oneTap.y) * mapSize.y;\n      return mix(resultX, resultY, coefY);\n    }\n    float CCGetShadowFactorSoft2X (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float offsetDepth = clipPos.z;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      float clipPos_offset_L = clipPos.x - oneTap.x;\n      float clipPos_offset_R = clipPos.x + oneTap.x;\n      float clipPos_offset_U = clipPos.y - oneTap.y;\n      float clipPos_offset_D = clipPos.y + oneTap.y;\n      float block0, block1, block2, block3, block4, block5, block6, block7, block8;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block4 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block5 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block6 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block7 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block8 = step(offsetDepth, dot(texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_U)).x);\n        block1 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset_U)).x);\n        block2 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_U)).x);\n        block3 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos.y)).x);\n        block4 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)).x);\n        block5 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos.y)).x);\n        block6 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_D)).x);\n        block7 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos.x, clipPos_offset_D)).x);\n        block8 = step(offsetDepth, texture(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_D)).x);\n      }\n      float coefX = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float coefY = mod(clipPos.y, oneTap.y) * mapSize.y;\n      float shadow = 0.0;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block3, block4, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block1, block2, coefX);\n      resultY = mix(block4, block5, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block3, block4, coefX);\n      resultY = mix(block6, block7, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      resultX = mix(block4, block5, coefX);\n      resultY = mix(block7, block8, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      return shadow * 0.25;\n    }\n    float CCGetSpotLightShadowFactorHard (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float shadow = 0.0;\n      float closestDepth = 0.0;\n      float depth = clipPos.z;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        closestDepth = dot(texture(cc_spotLightingMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));\n      } else {\n        closestDepth = texture(cc_spotLightingMap, clipPos.xy).x;\n      }\n      shadow = step(depth, closestDepth);\n      return shadow;\n    }\n    float CCGetSpotLightShadowFactorSoft (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float depth = 0.0;\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        depth = CCGetLinearDepth(worldPos);\n      } else {\n        depth = clipPos.z;\n      }\n      float bias = cc_shadowWHPBInfo.w;\n      vec2 oneTap = 1.0 / cc_shadowWHPBInfo.xy;\n      vec2 clipPos_offset = clipPos.xy + oneTap;\n      float block0, block1, block2, block3;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)).x);\n        block1 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos.y)).x);\n        block2 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset.y)).x);\n        block3 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos_offset.y)).x);\n      }\n      float coefX   = mod(clipPos.x, oneTap.x) * cc_shadowWHPBInfo.x;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block2, block3, coefX);\n      float coefY   = mod(clipPos.y, oneTap.y) * cc_shadowWHPBInfo.y;\n      return mix(resultX, resultY, coefY);\n    }\n    float CCGetSpotLightShadowFactorSoft2X (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float depth = 0.0;\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        depth = CCGetLinearDepth(worldPos);\n      } else {\n        depth = clipPos.z;\n      }\n      float bias = cc_shadowWHPBInfo.w;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      float clipPos_offset_L = clipPos.x - oneTap.x;\n      float clipPos_offset_R = clipPos.x + oneTap.x;\n      float clipPos_offset_U = clipPos.y - oneTap.y;\n      float clipPos_offset_D = clipPos.y + oneTap.y;\n      float block0, block1, block2, block3, block4, block5, block6, block7, block8;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block4 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block5 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block6 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block7 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block8 = step(depth, dot(texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_U)).x);\n        block1 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_U)).x);\n        block2 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_U)).x);\n        block3 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos.y)).x);\n        block4 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)).x);\n        block5 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos.y)).x);\n        block6 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_D)).x);\n        block7 = step(depth, texture(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_D)).x);\n        block8 = step(depth, texture(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_D)).x);\n      }\n      float coefX = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float coefY = mod(clipPos.y, oneTap.y) * mapSize.y;\n      float shadow = 0.0;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block3, block4, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block1, block2, coefX);\n      resultY = mix(block4, block5, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block3, block4, coefX);\n      resultY = mix(block6, block7, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      resultX = mix(block4, block5, coefX);\n      resultY = mix(block7, block8, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      return shadow * 0.25;\n    }\n  #endif\n  #if CC_USE_IBL\n    uniform samplerCube cc_environment;\n    vec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n        return textureLod(tex, coord, lod);\n    }\n    vec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n        return textureLod(tex, coord, lod);\n    }\n    vec3 unpackRGBE (vec4 rgbe) {\n      return rgbe.rgb * pow(1.1, rgbe.a * 255.0 - 128.0);\n    }\n    #if CC_USE_DIFFUSEMAP\n      uniform samplerCube cc_diffuseMap;\n    #endif\n  #endif\n  float GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n    vec3 NxH = cross(N, H);\n    float OneMinusNoHSqr = dot(NxH, NxH);\n    float a = roughness * roughness;\n    float n = NoH * a;\n    float p = a / (OneMinusNoHSqr + n * n);\n    return p * p;\n  }\n  float CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n    return (roughness * 0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n  }\n  vec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n    const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n    const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n    vec4 r = roughness * c0 + c1;\n    float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;\n    vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;\n    AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n    return specular * AB.x + AB.y;\n  }\n  #if USE_REFLECTION_DENOISE\n    vec3 GetEnvReflectionWithMipFiltering(vec3 R, float roughness, float mipCount, float denoiseIntensity) {\n      #if CC_USE_IBL\n      \tfloat mip = roughness * mipCount;\n      \tfloat delta = (dot(dFdx(R), dFdy(R))) * 1000.0;\n      \tfloat mipBias = mix(0.0, 5.0, clamp(delta, 0.0, 1.0));\n      \tvec4 biased = fragTextureLod(cc_environment, R, mip + mipBias);\n       \tvec4 filtered = texture(cc_environment, R);\n        #if CC_USE_IBL == 2\n        \tbiased.rgb = unpackRGBE(biased);\n        \tfiltered.rgb = unpackRGBE(filtered);\n        #else\n        \tbiased.rgb = SRGBToLinear(biased.rgb);\n        \tfiltered.rgb = SRGBToLinear(filtered.rgb);\n        #endif\n        return mix(biased.rgb, filtered.rgb, denoiseIntensity);\n      #else\n        return vec3(0.0, 0.0, 0.0);\n      #endif\n    }\n  #endif\n  struct StandardSurface {\n    vec4 albedo;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      vec3 position, position_fract_part;\n      #else\n      vec3 position;\n      #endif\n    vec3 normal;\n    vec3 emissive;\n    vec3 lightmap;\n    float lightmap_test;\n    float roughness;\n    float metallic;\n    float occlusion;\n  };\n  vec4 CCStandardShadingBase (StandardSurface s, vec4 shadowPos) {\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.0);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 L = normalize(-cc_mainLitDir.xyz);\n    vec3 H = normalize(L + V);\n    float NH = max(dot(N, H), 0.0);\n    float NL = max(dot(N, L), 0.0);\n    vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n    vec3 diffuseContrib = diffuse;\n    #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n      if (s.lightmap_test > 0.0001) {\n        finalColor = s.lightmap.rgb;\n      }\n    #else\n      diffuseContrib /= 3.14159265359;\n    #endif\n    vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n    vec3 dirlightContrib = (diffuseContrib + specularContrib);\n    float shadow = 1.0;\n    #if CC_RECEIVE_SHADOW\n      if (NL > 0.0 && cc_mainLitDir.w > 0.0) {\n          {\n            vec4 pos = ApplyShadowDepthBias_FaceNormal(shadowPos, N);\n            float pcf = cc_shadowWHPBInfo.z;\n            if (pcf > 1.9) shadow = CCGetShadowFactorSoft2X(pos);\n            else if (pcf > 0.9) shadow = CCGetShadowFactorSoft(pos);\n            else shadow = CCGetShadowFactorHard(pos);\n            shadow = mix(shadow, 1.0, cc_shadowNFLSInfo.w);\n          }\n      }\n    #endif\n    dirlightContrib *= shadow;\n    finalColor *= dirlightContrib;\n    float fAmb = 0.5 - N.y * 0.5;\n    vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb);\n    #if CC_USE_IBL\n      #if CC_USE_DIFFUSEMAP\n        vec4 diffuseMap = texture(cc_diffuseMap, N);\n        #if CC_USE_DIFFUSEMAP == 2\n          ambDiff = unpackRGBE(diffuseMap);\n        #else\n          ambDiff = SRGBToLinear(diffuseMap.rgb);\n        #endif\n      #endif\n      vec3 R = normalize(reflect(-V, N));\n      #if USE_REFLECTION_DENOISE\n        vec3 env = GetEnvReflectionWithMipFiltering(R, s.roughness, cc_ambientGround.w, 0.6);\n      #else\n        vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n        #if CC_USE_IBL == 2\n          vec3 env = unpackRGBE(envmap);\n        #else\n          vec3 env = SRGBToLinear(envmap.rgb);\n        #endif\n      #endif\n      finalColor += env * cc_ambientSky.w * specular * s.occlusion;\n    #endif\n    finalColor += ambDiff.rgb * cc_ambientSky.w * diffuse * s.occlusion;\n    finalColor += s.emissive;\n    return vec4(finalColor, s.albedo.a);\n  }\n  #if CC_PIPELINE_TYPE == 0\n  # define LIGHTS_PER_PASS 1\n  #else\n  # define LIGHTS_PER_PASS 10\n  #endif\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 0\n  layout(std140) uniform CCForwardLight {\n    highp vec4 cc_lightPos[LIGHTS_PER_PASS];\n    vec4 cc_lightColor[LIGHTS_PER_PASS];\n    vec4 cc_lightSizeRangeAngle[LIGHTS_PER_PASS];\n    vec4 cc_lightDir[LIGHTS_PER_PASS];\n  };\n  #endif\n  float SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n    float factor = distSqr * invSqrAttRadius;\n    float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n    return smoothFactor * smoothFactor;\n  }\n  float GetDistAtt (float distSqr, float invSqrAttRadius) {\n    float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n    attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n    return attenuation;\n  }\n  float GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n    float cd = dot(litDir, L);\n    float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n    return (attenuation * attenuation);\n  }\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 0\n  vec4 CCStandardShadingAdditive (StandardSurface s, vec4 shadowPos) {\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 diffuseContrib = diffuse / 3.14159265359;\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.0);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 finalColor = vec3(0.0);\n    int numLights = CC_PIPELINE_TYPE == 0 ? LIGHTS_PER_PASS : int(cc_lightDir[0].w);\n    for (int i = 0; i < LIGHTS_PER_PASS; i++) {\n      if (i >= numLights) break;\n      vec3 SLU = cc_lightPos[i].xyz - position;\n      vec3 SL = normalize(SLU);\n      vec3 SH = normalize(SL + V);\n      float SNL = max(dot(N, SL), 0.0);\n      float SNH = max(dot(N, SH), 0.0);\n      float distSqr = dot(SLU, SLU);\n      float litRadius = cc_lightSizeRangeAngle[i].x;\n      float litRadiusSqr = litRadius * litRadius;\n      float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n      float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n      attRadiusSqrInv *= attRadiusSqrInv;\n      float att = GetDistAtt(distSqr, attRadiusSqrInv);\n      vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n      if (cc_lightPos[i].w > 0.0) {\n        float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n        float cosOuter = cc_lightSizeRangeAngle[i].z;\n        float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n        float litAngleOffset = -cosOuter * litAngleScale;\n        att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n      }\n      vec3 lightColor = cc_lightColor[i].rgb;\n      float shadow = 1.0;\n      #if CC_RECEIVE_SHADOW\n        if (cc_lightPos[i].w > 0.0 && cc_lightSizeRangeAngle[i].w > 0.0) {\n            {\n              float pcf = cc_shadowWHPBInfo.z;\n              if (pcf > 1.9) shadow = CCGetSpotLightShadowFactorSoft2X(shadowPos, position);\n              else if (pcf > 0.9) shadow = CCGetSpotLightShadowFactorSoft(shadowPos, position);\n              else shadow = CCGetSpotLightShadowFactorHard(shadowPos, position);\n            }\n        }\n      #endif\n      lightColor *= shadow;\n      finalColor += SNL * lightColor * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n    }\n    return vec4(finalColor, 0.0);\n  }\n  #endif\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 1\n  layout(std430, binding = 4) readonly buffer b_ccLightsBuffer { vec4 b_ccLights[]; };\n  layout(std430, binding = 5) readonly buffer b_clusterLightIndicesBuffer { uint b_clusterLightIndices[]; };\n  layout(std430, binding = 6) readonly buffer b_clusterLightGridBuffer { uvec4 b_clusterLightGrid[]; };\n  struct CCLight\n  {\n    vec4 cc_lightPos;\n    vec4 cc_lightColor;\n    vec4 cc_lightSizeRangeAngle;\n    vec4 cc_lightDir;\n  };\n  struct Cluster\n  {\n    vec3 minBounds;\n    vec3 maxBounds;\n  };\n  struct LightGrid\n  {\n    uint offset;\n    uint ccLights;\n  };\n  CCLight getCCLight(uint i)\n  {\n    CCLight light;\n    light.cc_lightPos = b_ccLights[4u * i + 0u];\n    light.cc_lightColor = b_ccLights[4u * i + 1u];\n    light.cc_lightSizeRangeAngle = b_ccLights[4u * i + 2u];\n    light.cc_lightDir = b_ccLights[4u * i + 3u];\n    return light;\n  }\n  LightGrid getLightGrid(uint cluster)\n  {\n    uvec4 gridvec = b_clusterLightGrid[cluster];\n    LightGrid grid;\n    grid.offset = gridvec.x;\n    grid.ccLights = gridvec.y;\n    return grid;\n  }\n  uint getGridLightIndex(uint start, uint offset)\n  {\n    return b_clusterLightIndices[start + offset];\n  }\n  uint getClusterZIndex(vec4 worldPos)\n  {\n    float scale = float(24) / log(cc_nearFar.y / cc_nearFar.x);\n    float bias = -(float(24) * log(cc_nearFar.x) / log(cc_nearFar.y / cc_nearFar.x));\n    float eyeDepth = -(cc_matView * worldPos).z;\n    uint zIndex = uint(max(log(eyeDepth) * scale + bias, 0.0));\n    return zIndex;\n  }\n  uint getClusterIndex(vec4 fragCoord, vec4 worldPos)\n  {\n    uint zIndex = getClusterZIndex(worldPos);\n    float clusterSizeX = ceil(cc_viewPort.z / float(16));\n    float clusterSizeY = ceil(cc_viewPort.w / float(8));\n    uvec3 indices = uvec3(uvec2(fragCoord.xy / vec2(clusterSizeX, clusterSizeY)), zIndex);\n    uint cluster = (16u * 8u) * indices.z + 16u * indices.y + indices.x;\n    return cluster;\n  }\n  vec4 CCClusterShadingAdditive (StandardSurface s, vec4 shadowPos) {\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 diffuseContrib = diffuse / 3.14159265359;\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.001);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 finalColor = vec3(0.0);\n    uint cluster = getClusterIndex(gl_FragCoord, vec4(position, 1.0));\n    LightGrid grid = getLightGrid(cluster);\n    uint numLights = grid.ccLights;\n    for (uint i = 0u; i < 100u; i++) {\n      if (i >= numLights) break;\n      uint lightIndex = getGridLightIndex(grid.offset, i);\n      CCLight light = getCCLight(lightIndex);\n      vec3 SLU = light.cc_lightPos.xyz - position;\n      vec3 SL = normalize(SLU);\n      vec3 SH = normalize(SL + V);\n      float SNL = max(dot(N, SL), 0.001);\n      float SNH = max(dot(N, SH), 0.0);\n      float distSqr = dot(SLU, SLU);\n      float litRadius = light.cc_lightSizeRangeAngle.x;\n      float litRadiusSqr = litRadius * litRadius;\n      float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n      float attRadiusSqrInv = 1.0 / max(light.cc_lightSizeRangeAngle.y, 0.01);\n      attRadiusSqrInv *= attRadiusSqrInv;\n      float att = GetDistAtt(distSqr, attRadiusSqrInv);\n      vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n      if (light.cc_lightPos.w > 0.0) {\n        float cosInner = max(dot(-light.cc_lightDir.xyz, SL), 0.01);\n        float cosOuter = light.cc_lightSizeRangeAngle.z;\n        float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n        float litAngleOffset = -cosOuter * litAngleScale;\n        att *= GetAngleAtt(SL, -light.cc_lightDir.xyz, litAngleScale, litAngleOffset);\n      }\n      vec3 lightColor = light.cc_lightColor.rgb;\n      float shadow = 1.0;\n      #if CC_RECEIVE_SHADOW\n        if (light.cc_lightPos.w > 0.0) {\n            {\n              float pcf = cc_shadowWHPBInfo.z;\n              if (pcf > 1.9) shadow = CCGetSpotLightShadowFactorSoft2X(shadowPos, position);\n              else if (pcf > 0.9) shadow = CCGetSpotLightShadowFactorSoft(shadowPos, position);\n              else shadow = CCGetSpotLightShadowFactorHard(shadowPos, position);\n            }\n        }\n      #endif\n      lightColor *= shadow;\n      finalColor += SNL * lightColor * light.cc_lightColor.w * illum * att * (diffuseContrib + lspec);\n    }\n    return vec4(finalColor, 0.0);\n  }\n  #endif\n  vec3 ACESToneMap (vec3 color) {\n    color = min(color, vec3(8.0));\n    const float A = 2.51;\n    const float B = 0.03;\n    const float C = 2.43;\n    const float D = 0.59;\n    const float E = 0.14;\n    return (color * (A * color + B)) / (color * (C * color + D) + E);\n  }\n  vec4 CCFragOutput (vec4 color) {\n    #if CC_USE_HDR\n      color.rgb = ACESToneMap(color.rgb);\n    #endif\n    color.rgb = sqrt(color.rgb);\n    return color;\n  }\n  float LinearFog(vec4 pos) {\n    vec4 wPos = pos;\n    float cam_dis = distance(cc_cameraPos, wPos);\n    float fogStart = cc_fogBase.x;\n    float fogEnd = cc_fogBase.y;\n    return clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);\n  }\n  float ExpFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float fogStart = cc_fogBase.x;\n    float fogDensity = cc_fogBase.z;\n    float cam_dis = max(distance(cc_cameraPos, wPos) - fogStart, 0.0) / fogAtten * 4.;\n    float f = exp(-cam_dis * fogDensity);\n    return f;\n  }\n  float ExpSquaredFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float fogStart = cc_fogBase.x;\n    float fogDensity = cc_fogBase.z;\n    float cam_dis = max(distance(cc_cameraPos, wPos) - fogStart, 0.0) / fogAtten * 4.;\n    float f = exp(-cam_dis * cam_dis * fogDensity * fogDensity);\n    return f;\n  }\n  float LayeredFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float _FogTop = cc_fogAdd.x;\n    float _FogRange = cc_fogAdd.y;\n    vec3 camWorldProj = cc_cameraPos.xyz;\n    camWorldProj.y = 0.;\n    vec3 worldPosProj = wPos.xyz;\n    worldPosProj.y = 0.;\n    float fDeltaD = distance(worldPosProj, camWorldProj) / fogAtten * 2.0;\n    float fDeltaY, fDensityIntegral;\n    if (cc_cameraPos.y > _FogTop) {\n      if (wPos.y < _FogTop) {\n        fDeltaY = (_FogTop - wPos.y) / _FogRange * 2.0;\n        fDensityIntegral = fDeltaY * fDeltaY * 0.5;\n      } else {\n        fDeltaY = 0.;\n        fDensityIntegral = 0.;\n      }\n    } else {\n      if (wPos.y < _FogTop) {\n        float fDeltaA = (_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n        float fDeltaB = (_FogTop - wPos.y) / _FogRange * 2.;\n        fDeltaY = abs(fDeltaA - fDeltaB);\n        fDensityIntegral = abs((fDeltaA * fDeltaA * 0.5) - (fDeltaB * fDeltaB * 0.5));\n      } else {\n        fDeltaY = abs(_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n        fDensityIntegral = abs(fDeltaY * fDeltaY * 0.5);\n      }\n    }\n    float fDensity;\n    if (fDeltaY != 0.) {\n      fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;\n    } else {\n      fDensity = 0.;\n    }\n    float f = exp(-fDensity);\n    return f;\n  }\n  void CC_TRANSFER_FOG_BASE(vec4 pos, out float factor)\n  {\n    #if CC_USE_FOG == 0\n  \tfactor = LinearFog(pos);\n    #elif CC_USE_FOG == 1\n      factor = ExpFog(pos);\n    #elif CC_USE_FOG == 2\n      factor = ExpSquaredFog(pos);\n    #elif CC_USE_FOG == 3\n      factor = LayeredFog(pos);\n    #else\n      factor = 1.0;\n    #endif\n  }\n  void CC_APPLY_FOG_BASE(inout vec4 color, float factor) {\n    color = vec4(mix(cc_fogColor.rgb, color.rgb, factor), color.a);\n  }\n  vec2 signNotZero(vec2 v) {\n    return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);\n  }\n  vec3 oct_to_float32x3(vec2 e) {\n    vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));\n    if (v.z < 0.0) v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);\n    return normalize(v);\n  }\n  vec4 screen2WS(vec3 coord) {\n    vec3 ndc = vec3(\n  \t  2.0 * (coord.x - cc_viewPort.x) / cc_viewPort.z - 1.0,\n      2.0 * (coord.y - cc_viewPort.y) / cc_viewPort.w - 1.0,\n      2.0 * coord.z - 1.0);\n    vec4 world = ((cc_matViewProjInv) * (vec4(ndc, 1.0)));\n    world      = world / world.w;\n    return world;\n  }\n  in vec2 v_uv;\n  #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n      layout(location = 0) inout vec4 gbuffer_albedoMap;\n      layout(location = 1) inout vec4 gbuffer_normalMap;\n      layout(location = 2) inout vec4 gbuffer_emissiveMap;\n  #else\n    uniform sampler2D gbuffer_albedoMap;\n    uniform sampler2D gbuffer_normalMap;\n    uniform sampler2D gbuffer_emissiveMap;\n  #endif\n  uniform sampler2D depth_stencil;\n  #if !CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT || __VERSION__ >= 450\n    layout(location = 0) out vec4 fragColor;\n  #endif\n  void main () {\n    StandardSurface s;\n    #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n        vec4 albedoMap = gbuffer_albedoMap;\n        vec4 normalMap = gbuffer_normalMap;\n        vec4 emissiveMap = gbuffer_emissiveMap;\n    #else\n      vec4 albedoMap = texture(gbuffer_albedoMap,v_uv);\n      vec4 normalMap = texture(gbuffer_normalMap,v_uv);\n      vec4 emissiveMap = texture(gbuffer_emissiveMap,v_uv);\n    #endif\n    float depth = texture(depth_stencil, v_uv).x;\n    s.albedo = albedoMap;\n    vec3 position = screen2WS(vec3(gl_FragCoord.xy, depth)).xyz;\n    s.position = position;\n    s.roughness = normalMap.z;\n    s.normal = oct_to_float32x3(normalMap.xy);\n    s.metallic = normalMap.w;\n    s.emissive = emissiveMap.xyz;\n    s.occlusion = emissiveMap.w;\n    float fogFactor;\n    CC_TRANSFER_FOG_BASE(vec4(position, 1), fogFactor);\n    vec4 shadowPos;\n      shadowPos = cc_matLightViewProj * vec4(position, 1);\n    vec4 color = CCStandardShadingBase(s, shadowPos) +\n#if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 1\n                 CCClusterShadingAdditive(s, shadowPos);\n#else\n                 CCStandardShadingAdditive(s, shadowPos);\n#endif\n    CC_APPLY_FOG_BASE(color, fogFactor);\n    color = CCFragOutput(color);\n    #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n        gbuffer_emissiveMap = color;\n    #else\n      fragColor = color;\n    #endif\n  }"
      },
      "glsl1": {
        "vert": "\nprecision highp float;\nstruct StandardVertInput {\n  highp vec4 position;\n  vec3 normal;\n  vec4 tangent;\n};\nattribute vec3 a_position;\nattribute vec3 a_normal;\nattribute vec2 a_texCoord;\nattribute vec4 a_tangent;\nuniform highp vec4 cc_cameraPos;\nvarying vec2 v_uv;\nvoid main () {\n  vec4 position;\n    position = vec4(a_position, 1.0);\n  position.xy = cc_cameraPos.w == 0.0 ? vec2(position.xy.x, -position.xy.y) : position.xy;\n  gl_Position = vec4(position.x, position.y, 1.0, 1.0);\n  v_uv = a_texCoord;\n}",
        "frag": "\n#ifdef GL_EXT_shader_framebuffer_fetch\n#extension GL_EXT_shader_framebuffer_fetch: enable\n#endif\n#ifdef GL_OES_standard_derivatives\n#extension GL_OES_standard_derivatives: enable\n#endif\n#ifdef GL_EXT_shader_texture_lod\n#extension GL_EXT_shader_texture_lod: enable\n#endif\n  precision highp float;\n  uniform highp mat4 cc_matView;\n  uniform highp mat4 cc_matViewProjInv;\n  uniform highp vec4 cc_cameraPos;\n  uniform mediump vec4 cc_mainLitDir;\n  uniform mediump vec4 cc_mainLitColor;\n  uniform mediump vec4 cc_ambientSky;\n  uniform mediump vec4 cc_ambientGround;\n  uniform mediump vec4 cc_fogColor;\n  uniform mediump vec4 cc_fogBase;\n  uniform mediump vec4 cc_fogAdd;\n  uniform mediump vec4 cc_nearFar;\n  uniform mediump vec4 cc_viewPort;\n  vec3 SRGBToLinear (vec3 gamma) {\n    return gamma * gamma;\n  }\n  uniform highp mat4 cc_matLightView;\n  uniform highp mat4 cc_matLightViewProj;\n  uniform highp vec4 cc_shadowInvProjDepthInfo;\n  uniform highp vec4 cc_shadowProjDepthInfo;\n  uniform highp vec4 cc_shadowProjInfo;\n  uniform mediump vec4 cc_shadowNFLSInfo;\n  uniform mediump vec4 cc_shadowWHPBInfo;\n  uniform mediump vec4 cc_shadowLPNNInfo;\n    highp float unpackHighpData (float mainPart, float modPart) {\n      highp float data = mainPart;\n      return data + modPart;\n    }\n    highp float unpackHighpData (float mainPart, float modPart, const float modValue) {\n      highp float data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec2 unpackHighpData (vec2 mainPart, vec2 modPart) {\n      highp vec2 data = mainPart;\n      return data + modPart;\n    }\n    highp vec2 unpackHighpData (vec2 mainPart, vec2 modPart, const float modValue) {\n      highp vec2 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec3 unpackHighpData (vec3 mainPart, vec3 modPart) {\n      highp vec3 data = mainPart;\n      return data + modPart;\n    }\n    highp vec3 unpackHighpData (vec3 mainPart, vec3 modPart, const float modValue) {\n      highp vec3 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n    highp vec4 unpackHighpData (vec4 mainPart, vec4 modPart) {\n      highp vec4 data = mainPart;\n      return data + modPart;\n    }\n    highp vec4 unpackHighpData (vec4 mainPart, vec4 modPart, const float modValue) {\n      highp vec4 data = mainPart * modValue;\n      return data + modPart * modValue;\n    }\n  float CCGetLinearDepthFromViewSpace(vec3 viewPos) {\n    float dist = length(viewPos);\n    return (dist - cc_shadowNFLSInfo.x) / (cc_shadowNFLSInfo.y - cc_shadowNFLSInfo.x);\n  }\n  float CCGetLinearDepth(vec3 worldPos) {\n    vec4 viewStartPos = cc_matLightView * vec4(worldPos.xyz, 1.0);\n    return CCGetLinearDepthFromViewSpace(viewStartPos.xyz);\n  }\n  #if CC_RECEIVE_SHADOW\n    uniform highp sampler2D cc_shadowMap;\n    uniform highp sampler2D cc_spotLightingMap;\n    vec4 ApplyShadowDepthBias_FaceNormal(vec4 shadowPos, vec3 worldNormal)\n    {\n      vec4 newShadowPos = shadowPos;\n      if(cc_shadowLPNNInfo.z > 0.0001)\n      {\n        vec4 viewNormal = cc_matLightView * vec4(worldNormal, 0.0);\n        if(viewNormal.z < 0.1)\n          newShadowPos.xy += viewNormal.xy * cc_shadowProjInfo.xy * cc_shadowLPNNInfo.z * clamp(viewNormal.z, 0.001, 0.1);\n      }\n      return newShadowPos;\n    }\n    vec4 ApplyShadowDepthBias_Perspective(vec4 shadowPos, float viewspaceDepthBias)\n    {\n      vec3 viewSpacePos;\n      viewSpacePos.xy = shadowPos.xy * cc_shadowProjInfo.zw;\n      viewSpacePos.z = shadowPos.z * cc_shadowInvProjDepthInfo.x + shadowPos.w * cc_shadowInvProjDepthInfo.y;\n      viewSpacePos.xyz += cc_shadowProjDepthInfo.z * normalize(viewSpacePos.xyz) * viewspaceDepthBias;\n      vec4 clipSpacePos;\n      clipSpacePos.xy = viewSpacePos.xy * cc_shadowProjInfo.xy;\n      clipSpacePos.zw = viewSpacePos.z * cc_shadowProjDepthInfo.xz + vec2(cc_shadowProjDepthInfo.y, 0.0);\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        clipSpacePos.z = CCGetLinearDepthFromViewSpace(viewSpacePos.xyz);\n        clipSpacePos.z = (clipSpacePos.z * 2.0 - 1.0) * clipSpacePos.w;\n      }\n      return clipSpacePos;\n    }\n    vec4 ApplyShadowDepthBias_Orthographic(vec4 shadowPos, float viewspaceDepthBias)\n    {\n      float coeffA = cc_shadowProjDepthInfo.x;\n      float coeffB = cc_shadowProjDepthInfo.y;\n      float viewSpacePos_z = (shadowPos.z - coeffB) / coeffA;\n      viewSpacePos_z += viewspaceDepthBias;\n      vec4 result = shadowPos;\n      result.z = viewSpacePos_z * coeffA + coeffB;\n      return result;\n    }\n    float CCGetShadowFactorHard (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float shadow = 0.0;\n      float closestDepth = 0.0;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        closestDepth = dot(texture2D(cc_shadowMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));\n      } else {\n        closestDepth = texture2D(cc_shadowMap, clipPos.xy).x;\n      }\n      shadow = step(clipPos.z, closestDepth);\n      return shadow;\n    }\n    float CCGetShadowFactorSoft (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float offsetDepth = clipPos.z;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      vec2 clipPos_offset = clipPos.xy + oneTap;\n      float block0, block1, block2, block3;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos_offset.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos_offset.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos.x, clipPos.y)).x);\n        block1 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos_offset.x, clipPos.y)).x);\n        block2 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos.x, clipPos_offset.y)).x);\n        block3 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos_offset.x, clipPos_offset.y)).x);\n      }\n      float coefX   = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block2, block3, coefX);\n      float coefY   = mod(clipPos.y, oneTap.y) * mapSize.y;\n      return mix(resultX, resultY, coefY);\n    }\n    float CCGetShadowFactorSoft2X (vec4 shadowPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Orthographic(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float offsetDepth = clipPos.z;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      float clipPos_offset_L = clipPos.x - oneTap.x;\n      float clipPos_offset_R = clipPos.x + oneTap.x;\n      float clipPos_offset_U = clipPos.y - oneTap.y;\n      float clipPos_offset_D = clipPos.y + oneTap.y;\n      float block0, block1, block2, block3, block4, block5, block6, block7, block8;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos_offset_L, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block4 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block5 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos_offset_R, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block6 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block7 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos.x, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block8 = step(offsetDepth, dot(texture2D(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_U)).x);\n        block1 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos.x, clipPos_offset_U)).x);\n        block2 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_U)).x);\n        block3 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos_offset_L, clipPos.y)).x);\n        block4 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos.x, clipPos.y)).x);\n        block5 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos_offset_R, clipPos.y)).x);\n        block6 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos_offset_L, clipPos_offset_D)).x);\n        block7 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos.x, clipPos_offset_D)).x);\n        block8 = step(offsetDepth, texture2D(cc_shadowMap, vec2(clipPos_offset_R, clipPos_offset_D)).x);\n      }\n      float coefX = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float coefY = mod(clipPos.y, oneTap.y) * mapSize.y;\n      float shadow = 0.0;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block3, block4, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block1, block2, coefX);\n      resultY = mix(block4, block5, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block3, block4, coefX);\n      resultY = mix(block6, block7, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      resultX = mix(block4, block5, coefX);\n      resultY = mix(block7, block8, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      return shadow * 0.25;\n    }\n    float CCGetSpotLightShadowFactorHard (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float shadow = 0.0;\n      float closestDepth = 0.0;\n      float depth = clipPos.z;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        closestDepth = dot(texture2D(cc_spotLightingMap, clipPos.xy), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0));\n      } else {\n        closestDepth = texture2D(cc_spotLightingMap, clipPos.xy).x;\n      }\n      shadow = step(depth, closestDepth);\n      return shadow;\n    }\n    float CCGetSpotLightShadowFactorSoft (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float depth = 0.0;\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        depth = CCGetLinearDepth(worldPos);\n      } else {\n        depth = clipPos.z;\n      }\n      float bias = cc_shadowWHPBInfo.w;\n      vec2 oneTap = 1.0 / cc_shadowWHPBInfo.xy;\n      vec2 clipPos_offset = clipPos.xy + oneTap;\n      float block0, block1, block2, block3;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos_offset.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)).x);\n        block1 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos.y)).x);\n        block2 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset.y)).x);\n        block3 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos_offset.x, clipPos_offset.y)).x);\n      }\n      float coefX   = mod(clipPos.x, oneTap.x) * cc_shadowWHPBInfo.x;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block2, block3, coefX);\n      float coefY   = mod(clipPos.y, oneTap.y) * cc_shadowWHPBInfo.y;\n      return mix(resultX, resultY, coefY);\n    }\n    float CCGetSpotLightShadowFactorSoft2X (vec4 shadowPos, vec3 worldPos) {\n      vec4 clipPosNew = ApplyShadowDepthBias_Perspective(shadowPos, cc_shadowWHPBInfo.w);\n      vec3 clipPos = clipPosNew.xyz / clipPosNew.w * 0.5 + 0.5;\n      if (clipPos.x < 0.0 || clipPos.x > 1.0 ||\n          clipPos.y < 0.0 || clipPos.y > 1.0 ||\n          clipPos.z < 0.0 || clipPos.z > 1.0) { return 1.0; }\n      clipPos.xy = cc_cameraPos.w == 1.0 ? vec2(clipPos.xy.x, 1.0 - clipPos.xy.y) : clipPos.xy;\n      float depth = 0.0;\n      if (cc_shadowNFLSInfo.z > 0.000001) {\n        depth = CCGetLinearDepth(worldPos);\n      } else {\n        depth = clipPos.z;\n      }\n      float bias = cc_shadowWHPBInfo.w;\n      vec2 mapSize = cc_shadowWHPBInfo.xy;\n      vec2 oneTap = 1.0 / mapSize;\n      float clipPos_offset_L = clipPos.x - oneTap.x;\n      float clipPos_offset_R = clipPos.x + oneTap.x;\n      float clipPos_offset_U = clipPos.y - oneTap.y;\n      float clipPos_offset_D = clipPos.y + oneTap.y;\n      float block0, block1, block2, block3, block4, block5, block6, block7, block8;\n      if (cc_shadowLPNNInfo.y > 0.000001) {\n        block0 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block1 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block2 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_U)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block3 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block4 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block5 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos.y)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block6 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block7 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n        block8 = step(depth, dot(texture2D(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_D)), vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0)));\n      } else {\n        block0 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_U)).x);\n        block1 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_U)).x);\n        block2 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_U)).x);\n        block3 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos.y)).x);\n        block4 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos.y)).x);\n        block5 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos.y)).x);\n        block6 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos_offset_L, clipPos_offset_D)).x);\n        block7 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos.x, clipPos_offset_D)).x);\n        block8 = step(depth, texture2D(cc_spotLightingMap, vec2(clipPos_offset_R, clipPos_offset_D)).x);\n      }\n      float coefX = mod(clipPos.x, oneTap.x) * mapSize.x;\n      float coefY = mod(clipPos.y, oneTap.y) * mapSize.y;\n      float shadow = 0.0;\n      float resultX = mix(block0, block1, coefX);\n      float resultY = mix(block3, block4, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block1, block2, coefX);\n      resultY = mix(block4, block5, coefX);\n      shadow += mix(resultX , resultY, coefY);\n      resultX = mix(block3, block4, coefX);\n      resultY = mix(block6, block7, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      resultX = mix(block4, block5, coefX);\n      resultY = mix(block7, block8, coefX);\n      shadow += mix(resultX, resultY, coefY);\n      return shadow * 0.25;\n    }\n  #endif\n  #if CC_USE_IBL\n    uniform samplerCube cc_environment;\n    vec4 fragTextureLod (sampler2D tex, vec2 coord, float lod) {\n        #ifdef GL_EXT_shader_texture_lod\n          return texture2DLodEXT(tex, coord, lod);\n        #else\n          return texture2D(tex, coord, lod);\n        #endif\n    }\n    vec4 fragTextureLod (samplerCube tex, vec3 coord, float lod) {\n        #ifdef GL_EXT_shader_texture_lod\n          return textureCubeLodEXT(tex, coord, lod);\n        #else\n          return textureCube(tex, coord, lod);\n        #endif\n    }\n    vec3 unpackRGBE (vec4 rgbe) {\n      return rgbe.rgb * pow(1.1, rgbe.a * 255.0 - 128.0);\n    }\n    #if CC_USE_DIFFUSEMAP\n      uniform samplerCube cc_diffuseMap;\n    #endif\n  #endif\n  float GGXMobile (float roughness, float NoH, vec3 H, vec3 N) {\n    vec3 NxH = cross(N, H);\n    float OneMinusNoHSqr = dot(NxH, NxH);\n    float a = roughness * roughness;\n    float n = NoH * a;\n    float p = a / (OneMinusNoHSqr + n * n);\n    return p * p;\n  }\n  float CalcSpecular (float roughness, float NoH, vec3 H, vec3 N) {\n    return (roughness * 0.25 + 0.25) * GGXMobile(roughness, NoH, H, N);\n  }\n  vec3 BRDFApprox (vec3 specular, float roughness, float NoV) {\n    const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);\n    const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);\n    vec4 r = roughness * c0 + c1;\n    float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;\n    vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;\n    AB.y *= clamp(50.0 * specular.g, 0.0, 1.0);\n    return specular * AB.x + AB.y;\n  }\n  #if USE_REFLECTION_DENOISE\n    vec3 GetEnvReflectionWithMipFiltering(vec3 R, float roughness, float mipCount, float denoiseIntensity) {\n      #if CC_USE_IBL\n      \tfloat mip = roughness * mipCount;\n      \tfloat delta = (dot(dFdx(R), dFdy(R))) * 1000.0;\n      \tfloat mipBias = mix(0.0, 5.0, clamp(delta, 0.0, 1.0));\n      \tvec4 biased = fragTextureLod(cc_environment, R, mip + mipBias);\n       \tvec4 filtered = textureCube(cc_environment, R);\n        #if CC_USE_IBL == 2\n        \tbiased.rgb = unpackRGBE(biased);\n        \tfiltered.rgb = unpackRGBE(filtered);\n        #else\n        \tbiased.rgb = SRGBToLinear(biased.rgb);\n        \tfiltered.rgb = SRGBToLinear(filtered.rgb);\n        #endif\n        return mix(biased.rgb, filtered.rgb, denoiseIntensity);\n      #else\n        return vec3(0.0, 0.0, 0.0);\n      #endif\n    }\n  #endif\n  struct StandardSurface {\n    vec4 albedo;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      vec3 position, position_fract_part;\n      #else\n      vec3 position;\n      #endif\n    vec3 normal;\n    vec3 emissive;\n    vec3 lightmap;\n    float lightmap_test;\n    float roughness;\n    float metallic;\n    float occlusion;\n  };\n  vec4 CCStandardShadingBase (StandardSurface s, vec4 shadowPos) {\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.0);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 L = normalize(-cc_mainLitDir.xyz);\n    vec3 H = normalize(L + V);\n    float NH = max(dot(N, H), 0.0);\n    float NL = max(dot(N, L), 0.0);\n    vec3 finalColor = NL * cc_mainLitColor.rgb * cc_mainLitColor.w;\n    vec3 diffuseContrib = diffuse;\n    #if USE_LIGHTMAP && !USE_BATCHING && !CC_FORWARD_ADD\n      if (s.lightmap_test > 0.0001) {\n        finalColor = s.lightmap.rgb;\n      }\n    #else\n      diffuseContrib /= 3.14159265359;\n    #endif\n    vec3 specularContrib = specular * CalcSpecular(s.roughness, NH, H, N);\n    vec3 dirlightContrib = (diffuseContrib + specularContrib);\n    float shadow = 1.0;\n    #if CC_RECEIVE_SHADOW\n      if (NL > 0.0 && cc_mainLitDir.w > 0.0) {\n          {\n            vec4 pos = ApplyShadowDepthBias_FaceNormal(shadowPos, N);\n            float pcf = cc_shadowWHPBInfo.z;\n            if (pcf > 1.9) shadow = CCGetShadowFactorSoft2X(pos);\n            else if (pcf > 0.9) shadow = CCGetShadowFactorSoft(pos);\n            else shadow = CCGetShadowFactorHard(pos);\n            shadow = mix(shadow, 1.0, cc_shadowNFLSInfo.w);\n          }\n      }\n    #endif\n    dirlightContrib *= shadow;\n    finalColor *= dirlightContrib;\n    float fAmb = 0.5 - N.y * 0.5;\n    vec3 ambDiff = mix(cc_ambientSky.rgb, cc_ambientGround.rgb, fAmb);\n    #if CC_USE_IBL\n      #if CC_USE_DIFFUSEMAP\n        vec4 diffuseMap = textureCube(cc_diffuseMap, N);\n        #if CC_USE_DIFFUSEMAP == 2\n          ambDiff = unpackRGBE(diffuseMap);\n        #else\n          ambDiff = SRGBToLinear(diffuseMap.rgb);\n        #endif\n      #endif\n      vec3 R = normalize(reflect(-V, N));\n      #if USE_REFLECTION_DENOISE\n        vec3 env = GetEnvReflectionWithMipFiltering(R, s.roughness, cc_ambientGround.w, 0.6);\n      #else\n        vec4 envmap = fragTextureLod(cc_environment, R, s.roughness * cc_ambientGround.w);\n        #if CC_USE_IBL == 2\n          vec3 env = unpackRGBE(envmap);\n        #else\n          vec3 env = SRGBToLinear(envmap.rgb);\n        #endif\n      #endif\n      finalColor += env * cc_ambientSky.w * specular * s.occlusion;\n    #endif\n    finalColor += ambDiff.rgb * cc_ambientSky.w * diffuse * s.occlusion;\n    finalColor += s.emissive;\n    return vec4(finalColor, s.albedo.a);\n  }\n  #if CC_PIPELINE_TYPE == 0\n  # define LIGHTS_PER_PASS 1\n  #else\n  # define LIGHTS_PER_PASS 10\n  #endif\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 0\n  uniform highp vec4 cc_lightPos[LIGHTS_PER_PASS];\n  uniform vec4 cc_lightColor[LIGHTS_PER_PASS];\n  uniform vec4 cc_lightSizeRangeAngle[LIGHTS_PER_PASS];\n  uniform vec4 cc_lightDir[LIGHTS_PER_PASS];\n  #endif\n  float SmoothDistAtt (float distSqr, float invSqrAttRadius) {\n    float factor = distSqr * invSqrAttRadius;\n    float smoothFactor = clamp(1.0 - factor * factor, 0.0, 1.0);\n    return smoothFactor * smoothFactor;\n  }\n  float GetDistAtt (float distSqr, float invSqrAttRadius) {\n    float attenuation = 1.0 / max(distSqr, 0.01*0.01);\n    attenuation *= SmoothDistAtt(distSqr , invSqrAttRadius);\n    return attenuation;\n  }\n  float GetAngleAtt (vec3 L, vec3 litDir, float litAngleScale, float litAngleOffset) {\n    float cd = dot(litDir, L);\n    float attenuation = clamp(cd * litAngleScale + litAngleOffset, 0.0, 1.0);\n    return (attenuation * attenuation);\n  }\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 0\n  vec4 CCStandardShadingAdditive (StandardSurface s, vec4 shadowPos) {\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 diffuseContrib = diffuse / 3.14159265359;\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.0);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 finalColor = vec3(0.0);\n    int numLights = CC_PIPELINE_TYPE == 0 ? LIGHTS_PER_PASS : int(cc_lightDir[0].w);\n    for (int i = 0; i < LIGHTS_PER_PASS; i++) {\n      if (i >= numLights) break;\n      vec3 SLU = cc_lightPos[i].xyz - position;\n      vec3 SL = normalize(SLU);\n      vec3 SH = normalize(SL + V);\n      float SNL = max(dot(N, SL), 0.0);\n      float SNH = max(dot(N, SH), 0.0);\n      float distSqr = dot(SLU, SLU);\n      float litRadius = cc_lightSizeRangeAngle[i].x;\n      float litRadiusSqr = litRadius * litRadius;\n      float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n      float attRadiusSqrInv = 1.0 / max(cc_lightSizeRangeAngle[i].y, 0.01);\n      attRadiusSqrInv *= attRadiusSqrInv;\n      float att = GetDistAtt(distSqr, attRadiusSqrInv);\n      vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n      if (cc_lightPos[i].w > 0.0) {\n        float cosInner = max(dot(-cc_lightDir[i].xyz, SL), 0.01);\n        float cosOuter = cc_lightSizeRangeAngle[i].z;\n        float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n        float litAngleOffset = -cosOuter * litAngleScale;\n        att *= GetAngleAtt(SL, -cc_lightDir[i].xyz, litAngleScale, litAngleOffset);\n      }\n      vec3 lightColor = cc_lightColor[i].rgb;\n      float shadow = 1.0;\n      #if CC_RECEIVE_SHADOW\n        if (cc_lightPos[i].w > 0.0 && cc_lightSizeRangeAngle[i].w > 0.0) {\n            {\n              float pcf = cc_shadowWHPBInfo.z;\n              if (pcf > 1.9) shadow = CCGetSpotLightShadowFactorSoft2X(shadowPos, position);\n              else if (pcf > 0.9) shadow = CCGetSpotLightShadowFactorSoft(shadowPos, position);\n              else shadow = CCGetSpotLightShadowFactorHard(shadowPos, position);\n            }\n        }\n      #endif\n      lightColor *= shadow;\n      finalColor += SNL * lightColor * cc_lightColor[i].w * illum * att * (diffuseContrib + lspec);\n    }\n    return vec4(finalColor, 0.0);\n  }\n  #endif\n  #if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 1\n  readonly buffer b_ccLightsBuffer { vec4 b_ccLights[]; };\n  readonly buffer b_clusterLightIndicesBuffer { uint b_clusterLightIndices[]; };\n  readonly buffer b_clusterLightGridBuffer { uvec4 b_clusterLightGrid[]; };\n  struct CCLight\n  {\n    vec4 cc_lightPos;\n    vec4 cc_lightColor;\n    vec4 cc_lightSizeRangeAngle;\n    vec4 cc_lightDir;\n  };\n  struct Cluster\n  {\n    vec3 minBounds;\n    vec3 maxBounds;\n  };\n  struct LightGrid\n  {\n    uint offset;\n    uint ccLights;\n  };\n  CCLight getCCLight(uint i)\n  {\n    CCLight light;\n    light.cc_lightPos = b_ccLights[4u * i + 0u];\n    light.cc_lightColor = b_ccLights[4u * i + 1u];\n    light.cc_lightSizeRangeAngle = b_ccLights[4u * i + 2u];\n    light.cc_lightDir = b_ccLights[4u * i + 3u];\n    return light;\n  }\n  LightGrid getLightGrid(uint cluster)\n  {\n    uvec4 gridvec = b_clusterLightGrid[cluster];\n    LightGrid grid;\n    grid.offset = gridvec.x;\n    grid.ccLights = gridvec.y;\n    return grid;\n  }\n  uint getGridLightIndex(uint start, uint offset)\n  {\n    return b_clusterLightIndices[start + offset];\n  }\n  uint getClusterZIndex(vec4 worldPos)\n  {\n    float scale = float(24) / log(cc_nearFar.y / cc_nearFar.x);\n    float bias = -(float(24) * log(cc_nearFar.x) / log(cc_nearFar.y / cc_nearFar.x));\n    float eyeDepth = -(cc_matView * worldPos).z;\n    uint zIndex = uint(max(log(eyeDepth) * scale + bias, 0.0));\n    return zIndex;\n  }\n  uint getClusterIndex(vec4 fragCoord, vec4 worldPos)\n  {\n    uint zIndex = getClusterZIndex(worldPos);\n    float clusterSizeX = ceil(cc_viewPort.z / float(16));\n    float clusterSizeY = ceil(cc_viewPort.w / float(8));\n    uvec3 indices = uvec3(uvec2(fragCoord.xy / vec2(clusterSizeX, clusterSizeY)), zIndex);\n    uint cluster = (16u * 8u) * indices.z + 16u * indices.y + indices.x;\n    return cluster;\n  }\n  vec4 CCClusterShadingAdditive (StandardSurface s, vec4 shadowPos) {\n    vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);\n    vec3 specular = mix(vec3(0.04), s.albedo.rgb, s.metallic);\n    vec3 diffuseContrib = diffuse / 3.14159265359;\n    vec3 position;\n      #if CC_PLATFORM_ANDROID_AND_WEBGL && CC_ENABLE_WEBGL_HIGHP_STRUCT_VALUES\n      position = unpackHighpData(s.position, s.position_fract_part);\n      #else\n      position = s.position;\n      #endif\n    vec3 N = normalize(s.normal);\n    vec3 V = normalize(cc_cameraPos.xyz - position);\n    float NV = max(abs(dot(N, V)), 0.001);\n    specular = BRDFApprox(specular, s.roughness, NV);\n    vec3 finalColor = vec3(0.0);\n    uint cluster = getClusterIndex(gl_FragCoord, vec4(position, 1.0));\n    LightGrid grid = getLightGrid(cluster);\n    uint numLights = grid.ccLights;\n    for (uint i = 0u; i < 100u; i++) {\n      if (i >= numLights) break;\n      uint lightIndex = getGridLightIndex(grid.offset, i);\n      CCLight light = getCCLight(lightIndex);\n      vec3 SLU = light.cc_lightPos.xyz - position;\n      vec3 SL = normalize(SLU);\n      vec3 SH = normalize(SL + V);\n      float SNL = max(dot(N, SL), 0.001);\n      float SNH = max(dot(N, SH), 0.0);\n      float distSqr = dot(SLU, SLU);\n      float litRadius = light.cc_lightSizeRangeAngle.x;\n      float litRadiusSqr = litRadius * litRadius;\n      float illum = 3.14159265359 * (litRadiusSqr / max(litRadiusSqr , distSqr));\n      float attRadiusSqrInv = 1.0 / max(light.cc_lightSizeRangeAngle.y, 0.01);\n      attRadiusSqrInv *= attRadiusSqrInv;\n      float att = GetDistAtt(distSqr, attRadiusSqrInv);\n      vec3 lspec = specular * CalcSpecular(s.roughness, SNH, SH, N);\n      if (light.cc_lightPos.w > 0.0) {\n        float cosInner = max(dot(-light.cc_lightDir.xyz, SL), 0.01);\n        float cosOuter = light.cc_lightSizeRangeAngle.z;\n        float litAngleScale = 1.0 / max(0.001, cosInner - cosOuter);\n        float litAngleOffset = -cosOuter * litAngleScale;\n        att *= GetAngleAtt(SL, -light.cc_lightDir.xyz, litAngleScale, litAngleOffset);\n      }\n      vec3 lightColor = light.cc_lightColor.rgb;\n      float shadow = 1.0;\n      #if CC_RECEIVE_SHADOW\n        if (light.cc_lightPos.w > 0.0) {\n            {\n              float pcf = cc_shadowWHPBInfo.z;\n              if (pcf > 1.9) shadow = CCGetSpotLightShadowFactorSoft2X(shadowPos, position);\n              else if (pcf > 0.9) shadow = CCGetSpotLightShadowFactorSoft(shadowPos, position);\n              else shadow = CCGetSpotLightShadowFactorHard(shadowPos, position);\n            }\n        }\n      #endif\n      lightColor *= shadow;\n      finalColor += SNL * lightColor * light.cc_lightColor.w * illum * att * (diffuseContrib + lspec);\n    }\n    return vec4(finalColor, 0.0);\n  }\n  #endif\n  vec3 ACESToneMap (vec3 color) {\n    color = min(color, vec3(8.0));\n    const float A = 2.51;\n    const float B = 0.03;\n    const float C = 2.43;\n    const float D = 0.59;\n    const float E = 0.14;\n    return (color * (A * color + B)) / (color * (C * color + D) + E);\n  }\n  vec4 CCFragOutput (vec4 color) {\n    #if CC_USE_HDR\n      color.rgb = ACESToneMap(color.rgb);\n    #endif\n    color.rgb = sqrt(color.rgb);\n    return color;\n  }\n  float LinearFog(vec4 pos) {\n    vec4 wPos = pos;\n    float cam_dis = distance(cc_cameraPos, wPos);\n    float fogStart = cc_fogBase.x;\n    float fogEnd = cc_fogBase.y;\n    return clamp((fogEnd - cam_dis) / (fogEnd - fogStart), 0., 1.);\n  }\n  float ExpFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float fogStart = cc_fogBase.x;\n    float fogDensity = cc_fogBase.z;\n    float cam_dis = max(distance(cc_cameraPos, wPos) - fogStart, 0.0) / fogAtten * 4.;\n    float f = exp(-cam_dis * fogDensity);\n    return f;\n  }\n  float ExpSquaredFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float fogStart = cc_fogBase.x;\n    float fogDensity = cc_fogBase.z;\n    float cam_dis = max(distance(cc_cameraPos, wPos) - fogStart, 0.0) / fogAtten * 4.;\n    float f = exp(-cam_dis * cam_dis * fogDensity * fogDensity);\n    return f;\n  }\n  float LayeredFog(vec4 pos) {\n    vec4 wPos = pos;\n    float fogAtten = cc_fogAdd.z;\n    float _FogTop = cc_fogAdd.x;\n    float _FogRange = cc_fogAdd.y;\n    vec3 camWorldProj = cc_cameraPos.xyz;\n    camWorldProj.y = 0.;\n    vec3 worldPosProj = wPos.xyz;\n    worldPosProj.y = 0.;\n    float fDeltaD = distance(worldPosProj, camWorldProj) / fogAtten * 2.0;\n    float fDeltaY, fDensityIntegral;\n    if (cc_cameraPos.y > _FogTop) {\n      if (wPos.y < _FogTop) {\n        fDeltaY = (_FogTop - wPos.y) / _FogRange * 2.0;\n        fDensityIntegral = fDeltaY * fDeltaY * 0.5;\n      } else {\n        fDeltaY = 0.;\n        fDensityIntegral = 0.;\n      }\n    } else {\n      if (wPos.y < _FogTop) {\n        float fDeltaA = (_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n        float fDeltaB = (_FogTop - wPos.y) / _FogRange * 2.;\n        fDeltaY = abs(fDeltaA - fDeltaB);\n        fDensityIntegral = abs((fDeltaA * fDeltaA * 0.5) - (fDeltaB * fDeltaB * 0.5));\n      } else {\n        fDeltaY = abs(_FogTop - cc_cameraPos.y) / _FogRange * 2.;\n        fDensityIntegral = abs(fDeltaY * fDeltaY * 0.5);\n      }\n    }\n    float fDensity;\n    if (fDeltaY != 0.) {\n      fDensity = (sqrt(1.0 + ((fDeltaD / fDeltaY) * (fDeltaD / fDeltaY)))) * fDensityIntegral;\n    } else {\n      fDensity = 0.;\n    }\n    float f = exp(-fDensity);\n    return f;\n  }\n  void CC_TRANSFER_FOG_BASE(vec4 pos, out float factor)\n  {\n    #if CC_USE_FOG == 0\n  \tfactor = LinearFog(pos);\n    #elif CC_USE_FOG == 1\n      factor = ExpFog(pos);\n    #elif CC_USE_FOG == 2\n      factor = ExpSquaredFog(pos);\n    #elif CC_USE_FOG == 3\n      factor = LayeredFog(pos);\n    #else\n      factor = 1.0;\n    #endif\n  }\n  void CC_APPLY_FOG_BASE(inout vec4 color, float factor) {\n    color = vec4(mix(cc_fogColor.rgb, color.rgb, factor), color.a);\n  }\n  vec2 signNotZero(vec2 v) {\n    return vec2((v.x >= 0.0) ? +1.0 : -1.0, (v.y >= 0.0) ? +1.0 : -1.0);\n  }\n  vec3 oct_to_float32x3(vec2 e) {\n    vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));\n    if (v.z < 0.0) v.xy = (1.0 - abs(v.yx)) * signNotZero(v.xy);\n    return normalize(v);\n  }\n  vec4 screen2WS(vec3 coord) {\n    vec3 ndc = vec3(\n  \t  2.0 * (coord.x - cc_viewPort.x) / cc_viewPort.z - 1.0,\n      2.0 * (coord.y - cc_viewPort.y) / cc_viewPort.w - 1.0,\n      2.0 * coord.z - 1.0);\n    vec4 world = ((cc_matViewProjInv) * (vec4(ndc, 1.0)));\n    world      = world / world.w;\n    return world;\n  }\n  varying vec2 v_uv;\n  #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n  #else\n    uniform sampler2D gbuffer_albedoMap;\n    uniform sampler2D gbuffer_normalMap;\n    uniform sampler2D gbuffer_emissiveMap;\n  #endif\n  uniform sampler2D depth_stencil;\n  #if !CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT || __VERSION__ >= 450\n  #endif\n  void main () {\n    StandardSurface s;\n    #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n        vec4 albedoMap = gl_LastFragData[0];\n        vec4 normalMap = gl_LastFragData[1];\n        vec4 emissiveMap = gl_LastFragDat[2];\n    #else\n      vec4 albedoMap = texture2D(gbuffer_albedoMap,v_uv);\n      vec4 normalMap = texture2D(gbuffer_normalMap,v_uv);\n      vec4 emissiveMap = texture2D(gbuffer_emissiveMap,v_uv);\n    #endif\n    float depth = texture2D(depth_stencil, v_uv).x;\n    s.albedo = albedoMap;\n    vec3 position = screen2WS(vec3(gl_FragCoord.xy, depth)).xyz;\n    s.position = position;\n    s.roughness = normalMap.z;\n    s.normal = oct_to_float32x3(normalMap.xy);\n    s.metallic = normalMap.w;\n    s.emissive = emissiveMap.xyz;\n    s.occlusion = emissiveMap.w;\n    float fogFactor;\n    CC_TRANSFER_FOG_BASE(vec4(position, 1), fogFactor);\n    vec4 shadowPos;\n      shadowPos = cc_matLightViewProj * vec4(position, 1);\n    vec4 color = CCStandardShadingBase(s, shadowPos) +\n#if CC_ENABLE_CLUSTERED_LIGHT_CULLING == 1\n                 CCClusterShadingAdditive(s, shadowPos);\n#else\n                 CCStandardShadingAdditive(s, shadowPos);\n#endif\n    CC_APPLY_FOG_BASE(color, fogFactor);\n    color = CCFragOutput(color);\n    #if CC_DEVICE_CAN_BENEFIT_FROM_INPUT_ATTACHMENT\n        gl_FragData[2] = color;\n    #else\n      gl_FragColor = color;\n    #endif\n  }"
      },
      "builtins": {
        "globals": {
          "blocks": [
            {
              "name": "CCGlobal",
              "defines": []
            },
            {
              "name": "CCCamera",
              "defines": []
            },
            {
              "name": "CCShadow",
              "defines": []
            }
          ],
          "samplerTextures": [
            {
              "name": "cc_shadowMap",
              "defines": [
                "CC_RECEIVE_SHADOW"
              ]
            },
            {
              "name": "cc_spotLightingMap",
              "defines": [
                "CC_RECEIVE_SHADOW"
              ]
            },
            {
              "name": "cc_environment",
              "defines": [
                "CC_USE_IBL"
              ]
            },
            {
              "name": "cc_diffuseMap",
              "defines": [
                "CC_USE_IBL",
                "CC_USE_DIFFUSEMAP"
              ]
            }
          ],
          "buffers": [],
          "images": []
        },
        "locals": {
          "blocks": [
            {
              "name": "CCForwardLight",
              "defines": [
                "CC_ENABLE_CLUSTERED_LIGHT_CULLING"
              ]
            }
          ],
          "samplerTextures": [],
          "buffers": [],
          "images": []
        },
        "statistics": {
          "CC_EFFECT_USED_VERTEX_UNIFORM_VECTORS": 39,
          "CC_EFFECT_USED_FRAGMENT_UNIFORM_VECTORS": 59
        }
      },
      "defines": [
        {
          "name": "CC_RECEIVE_SHADOW",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_IBL",
          "type": "number",
          "defines": [],
          "range": [
            0,
            2
          ]
        },
        {
          "name": "CC_USE_DIFFUSEMAP",
          "type": "number",
          "defines": [
            "CC_USE_IBL"
          ],
          "range": [
            0,
            2
          ]
        },
        {
          "name": "USE_REFLECTION_DENOISE",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "USE_LIGHTMAP",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "USE_BATCHING",
          "type": "boolean",
          "defines": [
            "USE_LIGHTMAP"
          ]
        },
        {
          "name": "CC_FORWARD_ADD",
          "type": "boolean",
          "defines": [
            "USE_LIGHTMAP",
            "!USE_BATCHING"
          ]
        },
        {
          "name": "CC_PIPELINE_TYPE",
          "type": "number",
          "defines": [],
          "range": [
            0,
            1
          ]
        },
        {
          "name": "CC_FORCE_FORWARD_SHADING",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_HDR",
          "type": "boolean",
          "defines": []
        },
        {
          "name": "CC_USE_FOG",
          "type": "number",
          "defines": [],
          "range": [
            0,
            4
          ]
        }
      ],
      "name": "pipeline/deferred-lighting|lighting-vs|lighting-fs"
    }
  ],
  "combinations": [],
  "hideInEditor": false
}