IrradianceComputeSH.bsl 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. #include "$ENGINE$\ReflectionCubemapCommon.bslinc"
  2. #include "$ENGINE$\SHCommon.bslinc"
  3. technique IrradianceComputeSH
  4. {
  5. mixin ReflectionCubemapCommon;
  6. mixin SHCommon;
  7. code
  8. {
  9. struct SHCoeffsAndWeight
  10. {
  11. #if ORDER == 3
  12. SHVector3RGB coeffs;
  13. #else // Assuming order 5
  14. SHVector5RGB coeffs;
  15. #endif
  16. float weight;
  17. };
  18. SamplerState gInputSamp;
  19. TextureCube gInputTex;
  20. RWStructuredBuffer<SHCoeffsAndWeight> gOutput;
  21. [internal]
  22. cbuffer Params
  23. {
  24. uint gCubeFace;
  25. uint gFaceSize;
  26. uint2 gDispatchSize;
  27. }
  28. groupshared SHCoeffsAndWeight sCoeffs[TILE_WIDTH * TILE_HEIGHT];
  29. /**
  30. * Integrates area of a cube face projected onto the surface of the sphere, from [0, 0] to [u, v].
  31. * u & v expected in [-1, -1] to [1, 1] range.
  32. *
  33. * See http://www.rorydriscoll.com/2012/01/15/cubemap-texel-solid-angle/ for derivation.
  34. */
  35. float integrateProjectedCubeArea(float u, float v)
  36. {
  37. return atan2(u * v, sqrt(u * u + v * v + 1.0f));
  38. }
  39. /** Calculates solid angle of a texel projected onto a sphere. */
  40. float texelSolidAngle(float u, float v, float invFaceSize)
  41. {
  42. float x0 = u - invFaceSize;
  43. float x1 = u + invFaceSize;
  44. float y0 = v - invFaceSize;
  45. float y1 = v + invFaceSize;
  46. return integrateProjectedCubeArea(x1, y1)
  47. - integrateProjectedCubeArea(x0, y1)
  48. - integrateProjectedCubeArea(x1, y0)
  49. + integrateProjectedCubeArea(x0, y0);
  50. }
  51. [numthreads(TILE_WIDTH, TILE_HEIGHT, 1)]
  52. void csmain(
  53. uint groupIdx : SV_GroupIndex,
  54. uint3 groupId : SV_GroupID,
  55. uint3 dispatchThreadId : SV_DispatchThreadID)
  56. {
  57. SHCoeffsAndWeight data;
  58. data.weight = 0;
  59. SHZero(data.coeffs.R);
  60. SHZero(data.coeffs.G);
  61. SHZero(data.coeffs.B);
  62. float invFaceSize = 1.0f / gFaceSize;
  63. uint2 pixelCoords = dispatchThreadId.xy * PIXELS_PER_THREAD;
  64. uint2 pixelCoordsEnd = pixelCoords + uint2(PIXELS_PER_THREAD, PIXELS_PER_THREAD);
  65. for(uint y = pixelCoords.y; y < pixelCoordsEnd.y; y++)
  66. {
  67. for(uint x = pixelCoords.x; x < pixelCoordsEnd.x; x++)
  68. {
  69. // Ignore pixels out of valid range
  70. if (x >= gFaceSize || y >= gFaceSize)
  71. break;
  72. // Map from [0, size-1] to [-1.0 + invSize, 1.0 - invSize].
  73. // (+0.5 in order to sample center of texel)
  74. float u = 2.0f * (x + 0.5f) * invFaceSize - 1.0f;
  75. float v = 2.0f * (y + 0.5f) * invFaceSize - 1.0f;
  76. float3 dir = getDirFromCubeFace(gCubeFace, float2(u, v));
  77. dir = normalize(dir);
  78. // Need to calculate solid angle (weight) of the texel, as cube face corners have
  79. // much smaller solid angle, meaning many of them occupy the same area when projected
  80. // on a sphere. Without weighing that area would look too bright.
  81. float weight = texelSolidAngle(u, v, invFaceSize);
  82. #if ORDER == 3
  83. SHVector3 shBasis = SHBasis3(dir);
  84. #else // Assuming order 5
  85. SHVector5 shBasis = SHBasis5(dir);
  86. #endif
  87. float3 radiance = gInputTex.SampleLevel(gInputSamp, dir, 0).rgb;
  88. SHMultiplyAdd(data.coeffs.R, shBasis, radiance.r * weight);
  89. SHMultiplyAdd(data.coeffs.G, shBasis, radiance.g * weight);
  90. SHMultiplyAdd(data.coeffs.B, shBasis, radiance.b * weight);
  91. data.weight += weight;
  92. }
  93. }
  94. sCoeffs[groupIdx] = data;
  95. GroupMemoryBarrierWithGroupSync();
  96. int numThreads = TILE_WIDTH * TILE_HEIGHT;
  97. [unroll]
  98. for(int tc = numThreads / 2; tc > 0; tc >>= 1)
  99. {
  100. if(groupIdx < tc)
  101. {
  102. SHAdd(sCoeffs[groupIdx].coeffs.R, sCoeffs[groupIdx + tc].coeffs.R);
  103. SHAdd(sCoeffs[groupIdx].coeffs.G, sCoeffs[groupIdx + tc].coeffs.G);
  104. SHAdd(sCoeffs[groupIdx].coeffs.B, sCoeffs[groupIdx + tc].coeffs.B);
  105. sCoeffs[groupIdx].weight += sCoeffs[groupIdx + tc].weight;
  106. }
  107. GroupMemoryBarrierWithGroupSync();
  108. }
  109. if(groupIdx == 0)
  110. {
  111. uint faceOffset = gDispatchSize.x * gDispatchSize.y * gCubeFace;
  112. uint outputIdx = faceOffset + groupId.y * gDispatchSize.x + groupId.x;
  113. gOutput[outputIdx] = sCoeffs[0];
  114. }
  115. }
  116. };
  117. };