LightGridLLCreation.bsl 7.7 KB

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