LightGridLLCreation.bsl 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include "$ENGINE$\PerCameraData.bslinc"
  2. #define USE_LIGHT_GRID_INDICES 1
  3. #include "$ENGINE$\DirectLighting.bslinc"
  4. #include "$ENGINE$\ImageBasedLighting.bslinc"
  5. #include "$ENGINE$\LightGridCommon.bslinc"
  6. shader LightGridLLCreation
  7. {
  8. mixin PerCameraData;
  9. mixin LightData;
  10. mixin LightGridCommon;
  11. mixin ImageBasedLighting;
  12. featureset = HighEnd;
  13. code
  14. {
  15. StructuredBuffer<LightData> gLights;
  16. StructuredBuffer<ReflProbeData> gReflectionProbes;
  17. RWStructuredBuffer<uint> gLightsCounter;
  18. RWStructuredBuffer<uint> gLightsLLHeads;
  19. RWBuffer<uint4> gLightsLL;
  20. RWStructuredBuffer<uint> gProbesCounter;
  21. RWStructuredBuffer<uint> gProbesLLHeads;
  22. RWBuffer<uint2> gProbesLL;
  23. // Generates a an axis aligned bounding box in NDC and transforms it to view space.
  24. // Note: This will overlap other cells, so it might be better to use frustum planes
  25. // instead of AABB, although frustum testing procedure could result in more false positive
  26. void calcCellAABB(uint3 cellIdx, out float3 center, out float3 extent)
  27. {
  28. // Note:: AABB calculation in tiled deferred image based lighting shader uses less instructions than this,
  29. // see if it can be applied here.
  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].y);
  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 csmain(
  73. uint3 groupId : SV_GroupID,
  74. uint3 groupThreadId : SV_GroupThreadID,
  75. uint3 dispatchThreadId : SV_DispatchThreadID)
  76. {
  77. // Ignore pixels out of valid range
  78. if (any(dispatchThreadId.xy >= gGridSize.xy))
  79. return;
  80. uint maxNumLinks = gNumCells * gMaxNumLightsPerCell;
  81. uint cellIdx = (dispatchThreadId.z * gGridSize.y + dispatchThreadId.y) * gGridSize.x + dispatchThreadId.x;
  82. float3 cellCenter;
  83. float3 cellExtent;
  84. calcCellAABB(dispatchThreadId, cellCenter, cellExtent);
  85. for(uint type = 1; type < 3; ++type)
  86. {
  87. uint lightsStart = gLightStrides[type - 1];
  88. uint lightsEnd = lightsStart + gLightCounts[type];
  89. for(uint i = lightsStart; i < lightsEnd; ++i)
  90. {
  91. float4 lightPosition = mul(gMatView, float4(gLights[i].position, 1.0f));
  92. float lightRadius = gLights[i].boundRadius;
  93. // Calculate distance from box to light
  94. float3 distances = max(abs(lightPosition - cellCenter) - cellExtent, 0);
  95. float distSqrd = dot(distances, distances);
  96. if(distSqrd <= (lightRadius * lightRadius))
  97. {
  98. uint nextLink;
  99. InterlockedAdd(gLightsCounter[0], 1U, nextLink);
  100. if(nextLink < maxNumLinks)
  101. {
  102. uint prevLink;
  103. InterlockedExchange(gLightsLLHeads[cellIdx], nextLink, prevLink);
  104. gLightsLL[nextLink] = uint4(i, type, prevLink, 0);
  105. }
  106. }
  107. }
  108. }
  109. for(uint i = 0; i < gNumReflProbes; ++i)
  110. {
  111. float4 probePosition = mul(gMatView, float4(gReflectionProbes[i].position, 1.0f));
  112. float probeRadius = gReflectionProbes[i].radius;
  113. // Calculate distance from box to light
  114. float3 distances = max(abs(probePosition - cellCenter) - cellExtent, 0);
  115. float distSqrd = dot(distances, distances);
  116. if(distSqrd <= (probeRadius * probeRadius))
  117. {
  118. uint nextLink;
  119. InterlockedAdd(gProbesCounter[0], 1U, nextLink);
  120. if(nextLink < maxNumLinks)
  121. {
  122. uint prevLink;
  123. InterlockedExchange(gProbesLLHeads[cellIdx], nextLink, prevLink);
  124. gProbesLL[nextLink] = uint2(i, prevLink);
  125. }
  126. }
  127. }
  128. }
  129. };
  130. };