IrradianceComputeSH.bsl 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. #include "$ENGINE$\ReflectionCubemapCommon.bslinc"
  2. #include "$ENGINE$\SHCommon.bslinc"
  3. shader IrradianceComputeSH
  4. {
  5. mixin ReflectionCubemapCommon;
  6. mixin SHCommon;
  7. featureset = HighEnd;
  8. variations
  9. {
  10. SH_ORDER = { 3, 5 };
  11. };
  12. code
  13. {
  14. struct SHCoeffsAndWeight
  15. {
  16. SHVectorRGB coeffs;
  17. float weight;
  18. };
  19. SamplerState gInputSamp;
  20. TextureCube gInputTex;
  21. RWStructuredBuffer<SHCoeffsAndWeight> gOutput;
  22. [internal]
  23. cbuffer Params
  24. {
  25. uint gCubeFace;
  26. uint gFaceSize;
  27. uint2 gDispatchSize;
  28. }
  29. groupshared SHCoeffsAndWeight sCoeffs[TILE_WIDTH * TILE_HEIGHT];
  30. [numthreads(TILE_WIDTH, TILE_HEIGHT, 1)]
  31. void csmain(
  32. uint groupIdx : SV_GroupIndex,
  33. uint3 groupId : SV_GroupID,
  34. uint3 dispatchThreadId : SV_DispatchThreadID)
  35. {
  36. SHCoeffsAndWeight data;
  37. data.weight = 0;
  38. SHZero(data.coeffs.R);
  39. SHZero(data.coeffs.G);
  40. SHZero(data.coeffs.B);
  41. float invFaceSize = 1.0f / gFaceSize;
  42. uint2 pixelCoords = dispatchThreadId.xy * PIXELS_PER_THREAD;
  43. uint2 pixelCoordsEnd = pixelCoords + uint2(PIXELS_PER_THREAD, PIXELS_PER_THREAD);
  44. for(uint y = pixelCoords.y; y < pixelCoordsEnd.y; y++)
  45. {
  46. for(uint x = pixelCoords.x; x < pixelCoordsEnd.x; x++)
  47. {
  48. // Ignore pixels out of valid range
  49. if (x >= gFaceSize || y >= gFaceSize)
  50. break;
  51. // Map from [0, size-1] to [-1.0 + invSize, 1.0 - invSize].
  52. // (+0.5 in order to sample center of texel)
  53. float u = 2.0f * (x + 0.5f) * invFaceSize - 1.0f;
  54. float v = 2.0f * (y + 0.5f) * invFaceSize - 1.0f;
  55. float3 dir = getDirFromCubeFace(gCubeFace, float2(u, v));
  56. dir = normalize(dir);
  57. // Need to calculate solid angle (weight) of the texel, as cube face corners have
  58. // much smaller solid angle, meaning many of them occupy the same area when projected
  59. // on a sphere. Without weighing that area would look too bright.
  60. float weight = texelSolidAngle(u, v, invFaceSize);
  61. SHVector shBasis = SHBasis(dir);
  62. float3 radiance = gInputTex.SampleLevel(gInputSamp, dir, 0).rgb;
  63. SHMultiplyAdd(data.coeffs.R, shBasis, radiance.r * weight);
  64. SHMultiplyAdd(data.coeffs.G, shBasis, radiance.g * weight);
  65. SHMultiplyAdd(data.coeffs.B, shBasis, radiance.b * weight);
  66. data.weight += weight;
  67. }
  68. }
  69. sCoeffs[groupIdx] = data;
  70. GroupMemoryBarrierWithGroupSync();
  71. int numThreads = TILE_WIDTH * TILE_HEIGHT;
  72. [unroll]
  73. for(int tc = numThreads / 2; tc > 0; tc >>= 1)
  74. {
  75. if(groupIdx < tc)
  76. {
  77. SHAdd(sCoeffs[groupIdx].coeffs.R, sCoeffs[groupIdx + tc].coeffs.R);
  78. SHAdd(sCoeffs[groupIdx].coeffs.G, sCoeffs[groupIdx + tc].coeffs.G);
  79. SHAdd(sCoeffs[groupIdx].coeffs.B, sCoeffs[groupIdx + tc].coeffs.B);
  80. sCoeffs[groupIdx].weight += sCoeffs[groupIdx + tc].weight;
  81. }
  82. GroupMemoryBarrierWithGroupSync();
  83. }
  84. if(groupIdx == 0)
  85. {
  86. uint faceOffset = gDispatchSize.x * gDispatchSize.y * gCubeFace;
  87. uint outputIdx = faceOffset + groupId.y * gDispatchSize.x + groupId.x;
  88. gOutput[outputIdx] = sCoeffs[0];
  89. }
  90. }
  91. };
  92. };