LightGridLLCreation.bsl 8.9 KB

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