{
  "__type__": "cc.EffectAsset",
  "_name": "pipeline/cluster-culling",
  "_objFlags": 0,
  "__editorExtras__": {},
  "_native": "",
  "techniques": [
    {
      "name": "opaque",
      "passes": [
        {
          "pass": "cluster-culling-cs",
          "program": "pipeline/cluster-culling|cluster-main"
        }
      ]
    }
  ],
  "shaders": [
    {
      "blocks": [],
      "samplerTextures": [],
      "samplers": [],
      "textures": [],
      "buffers": [],
      "images": [],
      "subpassInputs": [],
      "attributes": [],
      "varyings": [],
      "fragColors": [],
      "descriptors": [
        {
          "rate": 0,
          "blocks": [],
          "samplerTextures": [],
          "samplers": [],
          "textures": [],
          "buffers": [],
          "images": [],
          "subpassInputs": []
        },
        {
          "rate": 1,
          "blocks": [],
          "samplerTextures": [],
          "samplers": [],
          "textures": [],
          "buffers": [],
          "images": [],
          "subpassInputs": []
        },
        {
          "rate": 2,
          "blocks": [],
          "samplerTextures": [],
          "samplers": [],
          "textures": [],
          "buffers": [],
          "images": [],
          "subpassInputs": []
        },
        {
          "rate": 3,
          "blocks": [
            {
              "tags": {},
              "name": "CCConst",
              "members": [
                {
                  "name": "cc_nearFar",
                  "typename": "vec4",
                  "type": 16,
                  "count": 1
                },
                {
                  "name": "cc_viewPort",
                  "typename": "vec4",
                  "type": 16,
                  "count": 1
                },
                {
                  "name": "cc_workGroup",
                  "typename": "vec4",
                  "type": 16,
                  "count": 1
                },
                {
                  "name": "cc_matView",
                  "typename": "mat4",
                  "type": 25,
                  "count": 1
                },
                {
                  "name": "cc_matProjInv",
                  "typename": "mat4",
                  "type": 25,
                  "count": 1
                }
              ],
              "defines": [],
              "stageFlags": 32,
              "rate": 3
            }
          ],
          "samplerTextures": [],
          "samplers": [],
          "textures": [],
          "buffers": [
            {
              "name": "b_ccLightsBuffer",
              "memoryAccess": 1,
              "defines": [],
              "stageFlags": 32,
              "binding": 0
            },
            {
              "name": "b_clustersBuffer",
              "memoryAccess": 1,
              "defines": [],
              "stageFlags": 32,
              "binding": 1
            },
            {
              "name": "b_clusterLightIndicesBuffer",
              "memoryAccess": 3,
              "defines": [],
              "stageFlags": 32,
              "binding": 2
            },
            {
              "name": "b_clusterLightGridBuffer",
              "memoryAccess": 3,
              "defines": [],
              "stageFlags": 32,
              "binding": 3
            },
            {
              "name": "b_globalIndexBuffer",
              "memoryAccess": 3,
              "defines": [],
              "stageFlags": 32,
              "binding": 4
            }
          ],
          "images": [],
          "subpassInputs": []
        }
      ],
      "hash": 3688014143,
      "glsl4": {
        "compute": "\nprecision highp float;\n#define LOCAL_SIZE_X 16u\n#define LOCAL_SIZE_Y 8u\n#define LOCAL_SIZE_Z 1u\n#define LOCAL_SIZE (LOCAL_SIZE_X * LOCAL_SIZE_Y * LOCAL_SIZE_Z)\nlayout(std140) uniform CCConst {\n  vec4 cc_nearFar;\n  vec4 cc_viewPort;\n  vec4 cc_workGroup;\n  mat4 cc_matView;\n  mat4 cc_matProjInv;\n};\nlayout(std430, set = 1, binding = 0) readonly buffer b_ccLightsBuffer { vec4 b_ccLights[]; };\nlayout(std430, set = 1, binding = 1) readonly buffer b_clustersBuffer { vec4 b_clusters[]; };\nlayout(std430, set = 1, binding = 2) buffer b_clusterLightIndicesBuffer { uint b_clusterLightIndices[]; };\nlayout(std430, set = 1, binding = 3) buffer b_clusterLightGridBuffer { uvec4 b_clusterLightGrid[]; };\nlayout(std430, set = 1, binding = 4) buffer b_globalIndexBuffer { uint b_globalIndex[]; };\nstruct CCLight {\n  vec4 cc_lightPos;\n  vec4 cc_lightColor;\n  vec4 cc_lightSizeRangeAngle;\n  vec4 cc_lightDir;\n  vec4 cc_lightBoundingSizeVS;\n};\nuint ccLightCount()\n{\n  return uint(b_ccLights[3].w);\n}\nCCLight getCCLight(uint i)\n{\n  CCLight light;\n  light.cc_lightPos = b_ccLights[5u * i + 0u];\n  light.cc_lightColor = b_ccLights[5u * i + 1u];\n  light.cc_lightSizeRangeAngle = b_ccLights[5u * i + 2u];\n  light.cc_lightDir = b_ccLights[5u * i + 3u];\n  light.cc_lightBoundingSizeVS = b_ccLights[5u * i + 4u];\n  return light;\n}\nstruct Cluster {\n  vec3 minBounds;\n  vec3 maxBounds;\n};\nstruct LightGrid {\n  uint offset;\n  uint ccLights;\n};\nCluster getCluster(uint index)\n{\n  Cluster cluster;\n  cluster.minBounds = b_clusters[2u * index + 0u].xyz;\n  cluster.maxBounds = b_clusters[2u * index + 1u].xyz;\n  return cluster;\n}\nbool ccLightIntersectsCluster(CCLight light, Cluster cluster)\n{\n  if (light.cc_lightPos.w > 0.0) {\n    vec3 halfExtents = (cluster.maxBounds - cluster.minBounds) * 0.5;\n    vec3 center = (cluster.minBounds + cluster.maxBounds) * 0.5;\n    float sphereRadius = sqrt(dot(halfExtents, halfExtents));\n    light.cc_lightDir = ((cc_matView) * (vec4(light.cc_lightDir.xyz, 1.0)));\n    light.cc_lightDir.xyz = (light.cc_lightDir - ((cc_matView) * (vec4(0,0,0, 1.0)))).xyz;\n    if (length(light.cc_lightDir.xyz) > 0.1) {\n      light.cc_lightDir.xyz = normalize(light.cc_lightDir.xyz);\n    }\n    vec3 v = center - light.cc_lightPos.xyz;\n    float lenSq = dot(v, v);\n    float v1Len = dot(v, light.cc_lightDir.xyz);\n    if(light.cc_lightDir.w == 1.0) {\n      v1Len = sqrt(lenSq);\n      return (v1Len <= sphereRadius  + light.cc_lightSizeRangeAngle.y);\n    }\n    float cosAngle = light.cc_lightSizeRangeAngle.z;\n    float sinAngle = sqrt(1.0 - cosAngle * cosAngle);\n    float distanceClosestPoint = cosAngle * sqrt(lenSq - v1Len * v1Len) - v1Len * sinAngle;\n    bool angleCull = distanceClosestPoint > sphereRadius;\n    bool frontCull = v1Len > sphereRadius + light.cc_lightSizeRangeAngle.y;\n    bool backCull = v1Len < -sphereRadius;\n    return !(angleCull || frontCull || backCull);\n  }\n  vec3 closest = max(cluster.minBounds, min(light.cc_lightPos.xyz, cluster.maxBounds));\n  vec3 dist = closest - light.cc_lightPos.xyz;\n  return dot(dist, dist) <= (light.cc_lightSizeRangeAngle.y * light.cc_lightSizeRangeAngle.y);\n}\nshared CCLight lights[LOCAL_SIZE];\nlayout(local_size_x = LOCAL_SIZE_X, local_size_y = LOCAL_SIZE_Y, local_size_z = LOCAL_SIZE_Z) in;\nvoid main()\n{\n  uint visibleLights[200];\n  uint visibleCount = 0u;\n  uint clusterIndex = gl_GlobalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y +\n    gl_GlobalInvocationID.y * gl_WorkGroupSize.x +\n    gl_GlobalInvocationID.x;\n  Cluster cluster = getCluster(clusterIndex);\n  uint lightCount = ccLightCount();\n  uint lightOffset = 0u;\n  while (lightOffset < lightCount) {\n    uint batchSize = min(LOCAL_SIZE, lightCount - lightOffset);\n    if (uint(gl_LocalInvocationIndex) < batchSize) {\n      uint lightIndex = lightOffset + gl_LocalInvocationIndex;\n      CCLight light = getCCLight(lightIndex);\n      light.cc_lightPos.xyz = ((cc_matView) * (vec4(light.cc_lightPos.xyz, 1.0))).xyz;\n      lights[gl_LocalInvocationIndex] = light;\n    }\n    barrier();\n    for (uint i = 0u; i < batchSize; i++) {\n      if (visibleCount < 200u && ccLightIntersectsCluster(lights[i], cluster)) {\n        visibleLights[visibleCount] = lightOffset + i;\n        visibleCount++;\n      }\n    }\n    lightOffset += batchSize;\n  }\n  barrier();\n  uint offset = 0u;\n  offset = atomicAdd(b_globalIndex[0], visibleCount);\n  for (uint i = 0u; i < visibleCount; i++) {\n    b_clusterLightIndices[offset + i] = visibleLights[i];\n  }\n  b_clusterLightGrid[clusterIndex] = uvec4(offset, visibleCount, 0, 0);\n}"
      },
      "glsl3": {
        "compute": "\nprecision highp float;\n#define LOCAL_SIZE_X 16u\n#define LOCAL_SIZE_Y 8u\n#define LOCAL_SIZE_Z 1u\n#define LOCAL_SIZE (LOCAL_SIZE_X * LOCAL_SIZE_Y * LOCAL_SIZE_Z)\nlayout(std140) uniform CCConst {\n  vec4 cc_nearFar;\n  vec4 cc_viewPort;\n  vec4 cc_workGroup;\n  mat4 cc_matView;\n  mat4 cc_matProjInv;\n};\nlayout(std430, binding = 0) readonly buffer b_ccLightsBuffer { vec4 b_ccLights[]; };\nlayout(std430, binding = 1) readonly buffer b_clustersBuffer { vec4 b_clusters[]; };\nlayout(std430, binding = 2) buffer b_clusterLightIndicesBuffer { uint b_clusterLightIndices[]; };\nlayout(std430, binding = 3) buffer b_clusterLightGridBuffer { uvec4 b_clusterLightGrid[]; };\nlayout(std430, binding = 4) buffer b_globalIndexBuffer { uint b_globalIndex[]; };\nstruct CCLight {\n  vec4 cc_lightPos;\n  vec4 cc_lightColor;\n  vec4 cc_lightSizeRangeAngle;\n  vec4 cc_lightDir;\n  vec4 cc_lightBoundingSizeVS;\n};\nuint ccLightCount()\n{\n  return uint(b_ccLights[3].w);\n}\nCCLight getCCLight(uint i)\n{\n  CCLight light;\n  light.cc_lightPos = b_ccLights[5u * i + 0u];\n  light.cc_lightColor = b_ccLights[5u * i + 1u];\n  light.cc_lightSizeRangeAngle = b_ccLights[5u * i + 2u];\n  light.cc_lightDir = b_ccLights[5u * i + 3u];\n  light.cc_lightBoundingSizeVS = b_ccLights[5u * i + 4u];\n  return light;\n}\nstruct Cluster {\n  vec3 minBounds;\n  vec3 maxBounds;\n};\nstruct LightGrid {\n  uint offset;\n  uint ccLights;\n};\nCluster getCluster(uint index)\n{\n  Cluster cluster;\n  cluster.minBounds = b_clusters[2u * index + 0u].xyz;\n  cluster.maxBounds = b_clusters[2u * index + 1u].xyz;\n  return cluster;\n}\nbool ccLightIntersectsCluster(CCLight light, Cluster cluster)\n{\n  if (light.cc_lightPos.w > 0.0) {\n    vec3 halfExtents = (cluster.maxBounds - cluster.minBounds) * 0.5;\n    vec3 center = (cluster.minBounds + cluster.maxBounds) * 0.5;\n    float sphereRadius = sqrt(dot(halfExtents, halfExtents));\n    light.cc_lightDir = ((cc_matView) * (vec4(light.cc_lightDir.xyz, 1.0)));\n    light.cc_lightDir.xyz = (light.cc_lightDir - ((cc_matView) * (vec4(0,0,0, 1.0)))).xyz;\n    if (length(light.cc_lightDir.xyz) > 0.1) {\n      light.cc_lightDir.xyz = normalize(light.cc_lightDir.xyz);\n    }\n    vec3 v = center - light.cc_lightPos.xyz;\n    float lenSq = dot(v, v);\n    float v1Len = dot(v, light.cc_lightDir.xyz);\n    if(light.cc_lightDir.w == 1.0) {\n      v1Len = sqrt(lenSq);\n      return (v1Len <= sphereRadius  + light.cc_lightSizeRangeAngle.y);\n    }\n    float cosAngle = light.cc_lightSizeRangeAngle.z;\n    float sinAngle = sqrt(1.0 - cosAngle * cosAngle);\n    float distanceClosestPoint = cosAngle * sqrt(lenSq - v1Len * v1Len) - v1Len * sinAngle;\n    bool angleCull = distanceClosestPoint > sphereRadius;\n    bool frontCull = v1Len > sphereRadius + light.cc_lightSizeRangeAngle.y;\n    bool backCull = v1Len < -sphereRadius;\n    return !(angleCull || frontCull || backCull);\n  }\n  vec3 closest = max(cluster.minBounds, min(light.cc_lightPos.xyz, cluster.maxBounds));\n  vec3 dist = closest - light.cc_lightPos.xyz;\n  return dot(dist, dist) <= (light.cc_lightSizeRangeAngle.y * light.cc_lightSizeRangeAngle.y);\n}\nshared CCLight lights[LOCAL_SIZE];\nlayout(local_size_x = LOCAL_SIZE_X, local_size_y = LOCAL_SIZE_Y, local_size_z = LOCAL_SIZE_Z) in;\nvoid main()\n{\n  uint visibleLights[200];\n  uint visibleCount = 0u;\n  uint clusterIndex = gl_GlobalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y +\n    gl_GlobalInvocationID.y * gl_WorkGroupSize.x +\n    gl_GlobalInvocationID.x;\n  Cluster cluster = getCluster(clusterIndex);\n  uint lightCount = ccLightCount();\n  uint lightOffset = 0u;\n  while (lightOffset < lightCount) {\n    uint batchSize = min(LOCAL_SIZE, lightCount - lightOffset);\n    if (uint(gl_LocalInvocationIndex) < batchSize) {\n      uint lightIndex = lightOffset + gl_LocalInvocationIndex;\n      CCLight light = getCCLight(lightIndex);\n      light.cc_lightPos.xyz = ((cc_matView) * (vec4(light.cc_lightPos.xyz, 1.0))).xyz;\n      lights[gl_LocalInvocationIndex] = light;\n    }\n    barrier();\n    for (uint i = 0u; i < batchSize; i++) {\n      if (visibleCount < 200u && ccLightIntersectsCluster(lights[i], cluster)) {\n        visibleLights[visibleCount] = lightOffset + i;\n        visibleCount++;\n      }\n    }\n    lightOffset += batchSize;\n  }\n  barrier();\n  uint offset = 0u;\n  offset = atomicAdd(b_globalIndex[0], visibleCount);\n  for (uint i = 0u; i < visibleCount; i++) {\n    b_clusterLightIndices[offset + i] = visibleLights[i];\n  }\n  b_clusterLightGrid[clusterIndex] = uvec4(offset, visibleCount, 0, 0);\n}"
      },
      "glsl1": {
        "compute": ""
      },
      "builtins": {
        "globals": {
          "blocks": [
            {
              "name": "CCConst",
              "defines": []
            }
          ],
          "samplerTextures": [],
          "buffers": [],
          "images": []
        },
        "locals": {
          "blocks": [],
          "samplerTextures": [],
          "buffers": [],
          "images": []
        },
        "statistics": {
          "CC_EFFECT_USED_COMPUTE_UNIFORM_VECTORS": 11
        }
      },
      "defines": [],
      "name": "pipeline/cluster-culling|cluster-main"
    }
  ],
  "combinations": [],
  "hideInEditor": false
}