cluster-culling.effect 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
  2. CCEffect %{
  3. techniques:
  4. - name: opaque
  5. passes:
  6. - compute: cluster-main
  7. pass: cluster-culling-cs
  8. }%
  9. CCProgram cluster-main %{
  10. precision highp float;
  11. #define LOCAL_SIZE_X 16u
  12. #define LOCAL_SIZE_Y 8u
  13. #define LOCAL_SIZE_Z 1u
  14. #define LOCAL_SIZE (LOCAL_SIZE_X * LOCAL_SIZE_Y * LOCAL_SIZE_Z)
  15. #pragma rate CCConst pass
  16. layout(std140) uniform CCConst {
  17. vec4 cc_nearFar;
  18. vec4 cc_viewPort;
  19. vec4 cc_workGroup;
  20. mat4 cc_matView;
  21. mat4 cc_matProjInv;
  22. };
  23. #pragma rate b_ccLightsBuffer pass
  24. #pragma glBinding(0)
  25. layout(std430) readonly buffer b_ccLightsBuffer { vec4 b_ccLights[]; };
  26. #pragma rate b_clustersBuffer pass
  27. #pragma glBinding(1)
  28. layout(std430) readonly buffer b_clustersBuffer { vec4 b_clusters[]; };
  29. #pragma rate b_clusterLightIndicesBuffer pass
  30. #pragma glBinding(2)
  31. layout(std430) buffer b_clusterLightIndicesBuffer { uint b_clusterLightIndices[]; };
  32. #pragma rate b_clusterLightGridBuffer pass
  33. #pragma glBinding(3)
  34. layout(std430) buffer b_clusterLightGridBuffer { uvec4 b_clusterLightGrid[]; };
  35. #pragma rate b_globalIndexBuffer pass
  36. #pragma glBinding(4)
  37. layout(std430) buffer b_globalIndexBuffer { uint b_globalIndex[]; };
  38. struct CCLight {
  39. vec4 cc_lightPos;
  40. vec4 cc_lightColor;
  41. vec4 cc_lightSizeRangeAngle;
  42. vec4 cc_lightDir;
  43. vec4 cc_lightBoundingSizeVS;
  44. };
  45. uint ccLightCount()
  46. {
  47. return uint(b_ccLights[3].w);
  48. }
  49. CCLight getCCLight(uint i)
  50. {
  51. CCLight light;
  52. light.cc_lightPos = b_ccLights[5u * i + 0u];
  53. light.cc_lightColor = b_ccLights[5u * i + 1u];
  54. light.cc_lightSizeRangeAngle = b_ccLights[5u * i + 2u];
  55. light.cc_lightDir = b_ccLights[5u * i + 3u];
  56. light.cc_lightBoundingSizeVS = b_ccLights[5u * i + 4u];
  57. return light;
  58. }
  59. struct Cluster {
  60. vec3 minBounds;
  61. vec3 maxBounds;
  62. };
  63. struct LightGrid {
  64. uint offset;
  65. uint ccLights;
  66. };
  67. Cluster getCluster(uint index)
  68. {
  69. Cluster cluster;
  70. cluster.minBounds = b_clusters[2u * index + 0u].xyz;
  71. cluster.maxBounds = b_clusters[2u * index + 1u].xyz;
  72. return cluster;
  73. }
  74. bool ccLightIntersectsCluster(CCLight light, Cluster cluster)
  75. {
  76. if (light.cc_lightPos.w > 0.0) {
  77. vec3 halfExtents = (cluster.maxBounds - cluster.minBounds) * 0.5;
  78. vec3 center = (cluster.minBounds + cluster.maxBounds) * 0.5;
  79. float sphereRadius = sqrt(dot(halfExtents, halfExtents));
  80. light.cc_lightDir = ((cc_matView) * (vec4(light.cc_lightDir.xyz, 1.0)));
  81. light.cc_lightDir.xyz = (light.cc_lightDir - ((cc_matView) * (vec4(0,0,0, 1.0)))).xyz;
  82. if (length(light.cc_lightDir.xyz) > 0.1) {
  83. light.cc_lightDir.xyz = normalize(light.cc_lightDir.xyz);
  84. }
  85. vec3 v = center - light.cc_lightPos.xyz;
  86. float lenSq = dot(v, v);
  87. float v1Len = dot(v, light.cc_lightDir.xyz);
  88. if(light.cc_lightDir.w == 1.0) {
  89. v1Len = sqrt(lenSq);
  90. return (v1Len <= sphereRadius + light.cc_lightSizeRangeAngle.y);
  91. }
  92. float cosAngle = light.cc_lightSizeRangeAngle.z;
  93. float sinAngle = sqrt(1.0 - cosAngle * cosAngle);
  94. float distanceClosestPoint = cosAngle * sqrt(lenSq - v1Len * v1Len) - v1Len * sinAngle;
  95. bool angleCull = distanceClosestPoint > sphereRadius;
  96. bool frontCull = v1Len > sphereRadius + light.cc_lightSizeRangeAngle.y;
  97. bool backCull = v1Len < -sphereRadius;
  98. return !(angleCull || frontCull || backCull);
  99. }
  100. vec3 closest = max(cluster.minBounds, min(light.cc_lightPos.xyz, cluster.maxBounds));
  101. vec3 dist = closest - light.cc_lightPos.xyz;
  102. return dot(dist, dist) <= (light.cc_lightSizeRangeAngle.y * light.cc_lightSizeRangeAngle.y);
  103. }
  104. shared CCLight lights[LOCAL_SIZE];
  105. layout(local_size_x = LOCAL_SIZE_X, local_size_y = LOCAL_SIZE_Y, local_size_z = LOCAL_SIZE_Z) in;
  106. void main()
  107. {
  108. uint visibleLights[200];
  109. uint visibleCount = 0u;
  110. uint clusterIndex = gl_GlobalInvocationID.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y +
  111. gl_GlobalInvocationID.y * gl_WorkGroupSize.x +
  112. gl_GlobalInvocationID.x;
  113. Cluster cluster = getCluster(clusterIndex);
  114. uint lightCount = ccLightCount();
  115. uint lightOffset = 0u;
  116. while (lightOffset < lightCount) {
  117. uint batchSize = min(LOCAL_SIZE, lightCount - lightOffset);
  118. if (uint(gl_LocalInvocationIndex) < batchSize) {
  119. uint lightIndex = lightOffset + gl_LocalInvocationIndex;
  120. CCLight light = getCCLight(lightIndex);
  121. light.cc_lightPos.xyz = ((cc_matView) * (vec4(light.cc_lightPos.xyz, 1.0))).xyz;
  122. lights[gl_LocalInvocationIndex] = light;
  123. }
  124. barrier();
  125. for (uint i = 0u; i < batchSize; i++) {
  126. if (visibleCount < 200u && ccLightIntersectsCluster(lights[i], cluster)) {
  127. visibleLights[visibleCount] = lightOffset + i;
  128. visibleCount++;
  129. }
  130. }
  131. lightOffset += batchSize;
  132. }
  133. barrier();
  134. uint offset = 0u;
  135. offset = atomicAdd(b_globalIndex[0], visibleCount);
  136. for (uint i = 0u; i < visibleCount; i++) {
  137. b_clusterLightIndices[offset + i] = visibleLights[i];
  138. }
  139. b_clusterLightGrid[clusterIndex] = uvec4(offset, visibleCount, 0, 0);
  140. }
  141. }%