ImportanceSampling.hlsl 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. // NOTE: To visualize some of these functions go to https://www.shadertoy.com/view/wsBBzV
  6. #pragma once
  7. #include <AnKi/Shaders/FastMathFunctions.hlsl>
  8. /// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
  9. /// Using reversebits instead of bitwise ops
  10. F32 radicalInverseVdC(U32 bits)
  11. {
  12. bits = reversebits(bits);
  13. return F32(bits) * 2.3283064365386963e-10; // / 0x100000000
  14. }
  15. /// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
  16. Vec2 hammersley2d(U32 i, U32 N)
  17. {
  18. return Vec2(F32(i) / F32(N), radicalInverseVdC(i));
  19. }
  20. /// Stolen from Unreal
  21. /// Returns three elements with 16 random bits each (0-0xffff)
  22. ///
  23. /// Use it like that:
  24. /// UVec3 seed = rand3DPCG16(UVec3(coord, frame % 8u));
  25. UVec3 rand3DPCG16(UVec3 v)
  26. {
  27. v = v * 1664525u + 1013904223u;
  28. v.x += v.y * v.z;
  29. v.y += v.z * v.x;
  30. v.z += v.x * v.y;
  31. v.x += v.y * v.z;
  32. v.y += v.z * v.x;
  33. v.z += v.x * v.y;
  34. return v >> 16u;
  35. }
  36. /// Stolen from Unreal
  37. /// It will return a uniform 2D point inside [0.0, 1.0]. For random use rand3DPCG16()
  38. ///
  39. /// Use it like that:
  40. /// Vec2 randFactors = hammersleyRandom16(sample, sampleCount, rand3DPCG16(...));
  41. Vec2 hammersleyRandom16(U32 sampleIdx, U32 sampleCount, UVec2 random)
  42. {
  43. const F32 e1 = frac(F32(sampleIdx) / F32(sampleCount) + F32(random.x) * (1.0 / 65536.0));
  44. const F32 e2 = F32((reversebits(sampleIdx) >> 16u) ^ random.y) * (1.0 / 65536.0);
  45. return Vec2(e1, e2);
  46. }
  47. /// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
  48. /// From a uniform 2D point inside a circle get a 3D point in the surface of a hemisphere. It's oriented in the +Z. uv is in [0, 1]
  49. ///
  50. /// Use it like that:
  51. /// Vec3 dir = hemisphereSampleCos(hammersleyRandom16(...));
  52. Vec3 hemisphereSampleUniform(Vec2 uv)
  53. {
  54. const F32 phi = uv.y * 2.0 * kPi;
  55. const F32 cosTheta = 1.0 - uv.x;
  56. const F32 sinTheta = sqrt(1.0 - cosTheta * cosTheta);
  57. return Vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
  58. }
  59. /// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
  60. /// Same as hemisphereSampleUniform but it distributes points closer to the z axis
  61. Vec3 hemisphereSampleCos(Vec2 uv)
  62. {
  63. const F32 phi = uv.y * 2.0 * kPi;
  64. const F32 cosTheta = sqrt(1.0 - uv.x);
  65. const F32 sinTheta = sqrt(1.0 - cosTheta * cosTheta);
  66. return Vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
  67. }
  68. /// PCG hash function.
  69. U32 hashPcg(U32 u)
  70. {
  71. const U32 state = u * 747796405u + 2891336453u;
  72. const U32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
  73. return (word >> 22u) ^ word;
  74. }
  75. U32 hilbertIndex(U32 posX, U32 posY)
  76. {
  77. const U32 level = 3u;
  78. const U32 width = 1u << level;
  79. U32 index = 0u;
  80. for(U32 curLevel = width / 2u; curLevel > 0u; curLevel /= 2u)
  81. {
  82. const U32 regionX = (posX & curLevel) > 0u;
  83. const U32 regionY = (posY & curLevel) > 0u;
  84. index += curLevel * curLevel * ((3u * regionX) ^ regionY);
  85. if(regionY == 0U)
  86. {
  87. if(regionX == 1U)
  88. {
  89. posX = U32(width - 1u) - posX;
  90. posY = U32(width - 1U) - posY;
  91. }
  92. const U32 temp = posX;
  93. posX = posY;
  94. posY = temp;
  95. }
  96. }
  97. return index;
  98. }
  99. /// Taken from XeGTAO code
  100. Vec2 spatioTemporalNoise(UVec2 fragCoord, U32 temporalIdx)
  101. {
  102. U32 index = hilbertIndex(fragCoord.x, fragCoord.y);
  103. index += 288u * (temporalIdx % 64u);
  104. return Vec2(frac(0.5f + index * Vec2(0.75487766624669276005f, 0.5698402909980532659114f)));
  105. }
  106. /// Generates a point on the unit sphere. The frameIndex can be used as a randomizer. No need to modulate the frameIndex.
  107. /// Usage:
  108. /// for(U32 s = 0; s < 32; ++s) {
  109. /// Vec3 point = generateUniformPointOnSphere(s, 32, frameIndex);
  110. /// }
  111. template<typename T, typename TInt>
  112. vector<T, 3> generateUniformPointOnSphere(TInt sampleIndex, TInt sampleCount, U32 frameIndex)
  113. {
  114. const T sampleIndexf = sampleIndex;
  115. const T sampleCountf = sampleCount;
  116. // Apply frame-dependent phase shift for randomness
  117. const T phaseShift = (frameIndex % sampleCount) * (T(k2Pi) / sampleCountf);
  118. // Compute spherical coordinates
  119. const T goldenRatio = 1.618;
  120. const T theta = fastAcos(T(1) - T(2) * (sampleIndexf + T(0.5)) / sampleCountf); // Evenly spaced latitudes
  121. const T phi = fmod((T(k2Pi * goldenRatio) * sampleIndexf + phaseShift), T(k2Pi)); // Golden ratio spiral with phase shift
  122. // Convert to Cartesian coordinates
  123. const T x = fastSin(theta) * fastCos(phi);
  124. const T y = fastSin(theta) * fastSin(phi);
  125. const T z = fastCos(theta);
  126. return normalize(vector<T, 3>(x, y, z));
  127. }
  128. /// Taken from SHforHLSL
  129. F32 sampleDirectionSpherePdf()
  130. {
  131. return 1.0 / (kPi * 4.0);
  132. }