LightGridLLCreation.bsl 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include "$ENGINE$\GBuffer.bslinc"
  2. #include "$ENGINE$\PerCameraData.bslinc"
  3. #include "$ENGINE$\LightingCommon.bslinc"
  4. #include "$ENGINE$\LightGridCommon.bslinc"
  5. Blocks =
  6. {
  7. Block PerCamera : auto("PerCamera");
  8. Block GridParams : auto("GridParams");
  9. };
  10. Technique
  11. : inherits("GBuffer")
  12. : inherits("PerCameraData")
  13. : inherits("LightingCommon")
  14. : inherits("LightGridCommon") =
  15. {
  16. Language = "HLSL11";
  17. Pass =
  18. {
  19. Compute =
  20. {
  21. StructuredBuffer<LightData> gLights : register(t0);
  22. RWBuffer<uint> gLinkedListCounter : register(u0);
  23. RWBuffer<uint> gLinkedListHeads : register(u1);
  24. RWBuffer<uint4> gLinkedList : register(u2);
  25. // Generates a an axis aligned bounding box in NDC and transforms it to view space.
  26. // Note: This will overlap other cells, so it might be better to use frustum planes
  27. // instead of AABB, although frustum testing procedure could result in more false positive
  28. void calcCellAABB(uint3 cellIdx, out float3 center, out float3 extent)
  29. {
  30. // Convert grid XY coordinates to clip coordinates
  31. float2 a = 2.0f / gGridSize.xy;
  32. float3 ndcMin;
  33. float3 ndcMax;
  34. ndcMin.xy = cellIdx.xy * a - float2(1.0f, 1.0f);
  35. ndcMax.xy = (cellIdx.xy + 1) * a - float2(1.0f, 1.0f);
  36. // Flip Y depending on render API, depending if Y in NDC is facing up or down
  37. // (We negate the value because we want NDC with Y flipped, so origin is top left)
  38. float flipY = -sign(gMatProj[1][1]);
  39. ndcMin.y *= flipY;
  40. ndcMax.y *= flipY;
  41. // Because we're viewing along negative Z, farther end is the minimum
  42. float viewZMin = calcViewZFromCellZ(cellIdx.z + 1);
  43. float viewZMax = calcViewZFromCellZ(cellIdx.z);
  44. ndcMin.z = convertToNDCZ(viewZMax);
  45. ndcMax.z = convertToNDCZ(viewZMin);
  46. float4 corner[8];
  47. // Near
  48. corner[0] = mul(gMatInvProj, float4(ndcMin.x, ndcMin.y, ndcMin.z, 1.0f));
  49. corner[1] = mul(gMatInvProj, float4(ndcMax.x, ndcMin.y, ndcMin.z, 1.0f));
  50. corner[2] = mul(gMatInvProj, float4(ndcMax.x, ndcMax.y, ndcMin.z, 1.0f));
  51. corner[3] = mul(gMatInvProj, float4(ndcMin.x, ndcMax.y, ndcMin.z, 1.0f));
  52. // Far
  53. corner[4] = mul(gMatInvProj, float4(ndcMin.x, ndcMin.y, ndcMax.z, 1.0f));
  54. corner[5] = mul(gMatInvProj, float4(ndcMax.x, ndcMin.y, ndcMax.z, 1.0f));
  55. corner[6] = mul(gMatInvProj, float4(ndcMax.x, ndcMax.y, ndcMax.z, 1.0f));
  56. corner[7] = mul(gMatInvProj, float4(ndcMin.x, ndcMax.y, ndcMax.z, 1.0f));
  57. [unroll]
  58. for(uint i = 0; i < 8; ++i)
  59. corner[i].xy /= corner[i].w;
  60. float3 viewMin = float3(corner[0].xy, viewZMin);
  61. float3 viewMax = float3(corner[0].xy, viewZMax);
  62. [unroll]
  63. for(uint i = 1; i < 8; ++i)
  64. {
  65. viewMin.xy = min(viewMin.xy, corner[i].xy);
  66. viewMax.xy = max(viewMax.xy, corner[i].xy);
  67. }
  68. extent = (viewMax - viewMin) * 0.5f;
  69. center = viewMin + extent;
  70. }
  71. [numthreads(THREADGROUP_SIZE, THREADGROUP_SIZE, THREADGROUP_SIZE)]
  72. void main(
  73. uint3 groupId : SV_GroupID,
  74. uint3 groupThreadId : SV_GroupThreadID,
  75. uint3 dispatchThreadId : SV_DispatchThreadID)
  76. {
  77. uint2 viewportMax = gViewportRectangle.xy + gViewportRectangle.zw;
  78. // Ignore pixels out of valid range
  79. if (all(dispatchThreadId.xy >= viewportMax))
  80. return;
  81. uint maxNumLinks = gNumCells * gMaxNumLightsPerCell;
  82. uint cellIdx = (dispatchThreadId.z * gGridSize.y + dispatchThreadId.y) * gGridSize.x + dispatchThreadId.x;
  83. float3 cellCenter;
  84. float3 cellExtent;
  85. calcCellAABB(dispatchThreadId, cellCenter, cellExtent);
  86. for(uint type = 1; type < 3; ++type)
  87. {
  88. uint lightOffset = gLightOffsets[type - 1];
  89. uint lightEnd = gLightOffsets[type];
  90. for(uint i = lightOffset; i < lightEnd; ++i)
  91. {
  92. float4 lightPosition = mul(gMatView, float4(gLights[i].position, 1.0f));
  93. float lightRadius = gLights[i].radius;
  94. // Calculate distance from box to light
  95. float3 distances = max(abs(lightPosition - cellCenter) - cellExtent, 0);
  96. float distSqrd = dot(distances, distances);
  97. if(distSqrd <= (lightRadius * lightRadius))
  98. {
  99. uint nextLink;
  100. InterlockedAdd(gLinkedListCounter[0], 1U, nextLink);
  101. if(nextLink < maxNumLinks)
  102. {
  103. uint prevLink;
  104. InterlockedExchange(gLinkedListHeads[cellIdx], nextLink, prevLink);
  105. gLinkedList[nextLink] = uint4(i, type, prevLink, 0);
  106. }
  107. }
  108. }
  109. }
  110. }
  111. };
  112. };
  113. };
  114. Technique
  115. : inherits("GBuffer")
  116. : inherits("PerCameraData")
  117. : inherits("LightingCommon")
  118. : inherits("LightGridCommon") =
  119. {
  120. Language = "GLSL";
  121. Pass =
  122. {
  123. Compute =
  124. {
  125. layout (local_size_x = THREADGROUP_SIZE, local_size_y = THREADGROUP_SIZE, local_size_z = THREADGROUP_SIZE) in;
  126. layout(std430, binding = 1) readonly buffer gLights
  127. {
  128. LightData[] gLightsData;
  129. };
  130. layout(binding = 2, r32ui) uniform uimageBuffer gLinkedListCounter;
  131. layout(binding = 3, r32ui) uniform uimageBuffer gLinkedListHeads;
  132. layout(binding = 5, rgba32ui) uniform uimageBuffer gLinkedList;
  133. void calcCellAABB(uvec3 cellIdx, out vec3 center, out vec3 extent)
  134. {
  135. // Convert grid XY coordinates to clip coordinates
  136. vec2 a = 2.0f / gGridSize.xy;
  137. vec3 ndcMin;
  138. vec3 ndcMax;
  139. ndcMin.xy = cellIdx.xy * a - vec2(1.0f, 1.0f);
  140. ndcMax.xy = (cellIdx.xy + 1) * a - vec2(1.0f, 1.0f);
  141. // Flip Y depending on render API, depending if Y in NDC is facing up or down
  142. // (We negate the value because we want NDC with Y flipped, so origin is top left)
  143. float flipY = -sign(gMatProj[1][1]);
  144. ndcMin.y *= flipY;
  145. ndcMax.y *= flipY;
  146. // Because we're viewing along negative Z, farther end is the minimum
  147. float viewZMin = calcViewZFromCellZ(cellIdx.z + 1);
  148. float viewZMax = calcViewZFromCellZ(cellIdx.z);
  149. ndcMin.z = convertToNDCZ(viewZMax);
  150. ndcMax.z = convertToNDCZ(viewZMin);
  151. vec4 corner[8];
  152. // Near
  153. corner[0] = gMatInvProj * vec4(ndcMin.x, ndcMin.y, ndcMin.z, 1.0f);
  154. corner[1] = gMatInvProj * vec4(ndcMax.x, ndcMin.y, ndcMin.z, 1.0f);
  155. corner[2] = gMatInvProj * vec4(ndcMax.x, ndcMax.y, ndcMin.z, 1.0f);
  156. corner[3] = gMatInvProj * vec4(ndcMin.x, ndcMax.y, ndcMin.z, 1.0f);
  157. // Far
  158. corner[4] = gMatInvProj * vec4(ndcMin.x, ndcMin.y, ndcMax.z, 1.0f);
  159. corner[5] = gMatInvProj * vec4(ndcMax.x, ndcMin.y, ndcMax.z, 1.0f);
  160. corner[6] = gMatInvProj * vec4(ndcMax.x, ndcMax.y, ndcMax.z, 1.0f);
  161. corner[7] = gMatInvProj * vec4(ndcMin.x, ndcMax.y, ndcMax.z, 1.0f);
  162. for(uint i = 0; i < 8; ++i)
  163. corner[i].xy /= corner[i].w;
  164. vec3 viewMin = vec3(corner[0].xy, viewZMin);
  165. vec3 viewMax = vec3(corner[0].xy, viewZMax);
  166. for(uint i = 1; i < 8; ++i)
  167. {
  168. viewMin.xy = min(viewMin.xy, corner[i].xy);
  169. viewMax.xy = max(viewMax.xy, corner[i].xy);
  170. }
  171. extent = (viewMax - viewMin) * 0.5f;
  172. center = viewMin + extent;
  173. }
  174. void main()
  175. {
  176. uvec2 viewportMax = gViewportRectangle.xy + gViewportRectangle.zw;
  177. // Ignore pixels out of valid range
  178. if (all(greaterThanEqual(gl_GlobalInvocationID.xy, viewportMax)))
  179. return;
  180. uint maxNumLinks = gNumCells * gMaxNumLightsPerCell;
  181. uint cellIdx = (gl_GlobalInvocationID.z * gGridSize.y + gl_GlobalInvocationID.y) * gGridSize.x + gl_GlobalInvocationID.x;
  182. vec3 cellCenter;
  183. vec3 cellExtent;
  184. calcCellAABB(gl_GlobalInvocationID, cellCenter, cellExtent);
  185. for(uint type = 1; type < 3; ++type)
  186. {
  187. uint lightOffset = gLightOffsets[type - 1];
  188. uint lightEnd = gLightOffsets[type];
  189. for(uint i = lightOffset; i < lightEnd; ++i)
  190. {
  191. vec4 lightPosition = gMatView * vec4(gLightsData[i].position, 1.0f);
  192. float lightRadius = gLightsData[i].radius;
  193. // Calculate distance from box to light
  194. vec3 distances = max(abs(lightPosition.xyz - cellCenter) - cellExtent, 0);
  195. float distSqrd = dot(distances, distances);
  196. if(distSqrd <= (lightRadius * lightRadius))
  197. {
  198. uint nextLink = imageAtomicAdd(gLinkedListCounter, 0, 1U);
  199. if(nextLink < maxNumLinks)
  200. {
  201. uint prevLink = imageAtomicExchange(gLinkedListHeads, int(cellIdx), nextLink);
  202. imageStore(gLinkedList, int(nextLink), uvec4(i, type, prevLink, 0));
  203. }
  204. }
  205. }
  206. }
  207. }
  208. };
  209. };
  210. };