Ei kuvausta
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SobolSampling.hlsl 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #ifndef _SAMPLING_SOBOLSAMPLING_HLSL_
  2. #define _SAMPLING_SOBOLSAMPLING_HLSL_
  3. #define SOBOL_MATRIX_SIZE 52
  4. #define SOBOL_MATRICES_COUNT 1024
  5. #include "SamplingResources.hlsl"
  6. #include "Hashes.hlsl"
  7. #include "Common.hlsl"
  8. // HLSLcc cannot correctly translate `reversebits(x)` for large unsigned integers.
  9. // Therefore, when using HLSLcc, we use our own implementation. https://jira.unity3d.com/browse/GFXFEAT-629
  10. #ifdef UNITY_COMPILER_HLSLCC
  11. uint ReverseBitsSafe(uint x)
  12. {
  13. x = ((x >> 1) & 0x55555555u) | ((x & 0x55555555u) << 1);
  14. x = ((x >> 2) & 0x33333333u) | ((x & 0x33333333u) << 2);
  15. x = ((x >> 4) & 0x0f0f0f0fu) | ((x & 0x0f0f0f0fu) << 4);
  16. x = ((x >> 8) & 0x00ff00ffu) | ((x & 0x00ff00ffu) << 8);
  17. x = ((x >> 16) & 0xffffu) | ((x & 0xffffu) << 16);
  18. return x;
  19. }
  20. #else
  21. #define ReverseBitsSafe reversebits
  22. #endif
  23. // See https://psychopath.io/post/2021_01_30_building_a_better_lk_hash
  24. uint LaineKarrasPermutation(uint x, uint seed)
  25. {
  26. x ^= x * 0x3d20adea;
  27. x += seed;
  28. x *= (seed >> 16) | 1;
  29. x ^= x * 0x05526c56;
  30. x ^= x * 0x53a22864;
  31. return x;
  32. }
  33. uint NestedUniformOwenScramble(uint x, uint seed)
  34. {
  35. x = ReverseBitsSafe(x);
  36. x = LaineKarrasPermutation(x, seed);
  37. x = ReverseBitsSafe(x);
  38. return x;
  39. }
  40. //See https://psychopath.io/post/2022_08_14_a_fast_hash_for_base_4_owen_scrambling
  41. uint LaineKarrasStylePermutationBase4(uint x, uint seed)
  42. {
  43. x ^= x * 0x3d20adeau;
  44. x ^= (x >> 1) & (x << 1) & 0x55555555u;
  45. x += seed;
  46. x *= (seed >> 16) | 1;
  47. x ^= (x >> 1) & (x << 1) & 0x55555555u;
  48. x ^= x * 0x05526c56u;
  49. x ^= x * 0x53a22864u;
  50. return x;
  51. }
  52. uint NestedUniformScrambleBase4(uint x, uint seed)
  53. {
  54. x = ReverseBitsSafe(x);
  55. x = LaineKarrasStylePermutationBase4(x, seed);
  56. x = ReverseBitsSafe(x);
  57. return x;
  58. }
  59. // "Insert" a 0 bit after each of the 16 low bits of x.
  60. // Ref: https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
  61. uint Part1By1(uint x)
  62. {
  63. x &= 0x0000ffff; // x = ---- ---- ---- ---- fedc ba98 7654 3210
  64. x = (x ^ (x << 8)) & 0x00ff00ff; // x = ---- ---- fedc ba98 ---- ---- 7654 3210
  65. x = (x ^ (x << 4)) & 0x0f0f0f0f; // x = ---- fedc ---- ba98 ---- 7654 ---- 3210
  66. x = (x ^ (x << 2)) & 0x33333333; // x = --fe --dc --ba --98 --76 --54 --32 --10
  67. x = (x ^ (x << 1)) & 0x55555555; // x = -f-e -d-c -b-a -9-8 -7-6 -5-4 -3-2 -1-0
  68. return x;
  69. }
  70. uint EncodeMorton2D(uint2 coord)
  71. {
  72. return (Part1By1(coord.y) << 1) + Part1By1(coord.x);
  73. }
  74. uint SobolSampleUint(uint index, int dimension, uint indexMaxBitCount)
  75. {
  76. uint result = 0;
  77. #ifdef UNIFIED_RT_BACKEND_HARDWARE
  78. // Raytracing tracing shaders compile only with unrolled loop, but unrolling fails in the compute path.
  79. // TODO: test again when Unity updates the shader compiler
  80. [unroll]
  81. #endif
  82. for (uint i = dimension * SOBOL_MATRIX_SIZE; i < dimension * SOBOL_MATRIX_SIZE + indexMaxBitCount; index >>= 1, ++i)
  83. {
  84. result ^= _SobolMatricesBuffer[i] * (index & 1);
  85. }
  86. return result;
  87. }
  88. uint SobolSampleUint(uint2 index64, uint dimension)
  89. {
  90. uint result = 0;
  91. uint i = dimension * SOBOL_MATRIX_SIZE;
  92. for (; i < dimension * SOBOL_MATRIX_SIZE + 32; index64.x >>= 1, ++i)
  93. {
  94. result ^= _SobolMatricesBuffer[i] * (index64.x & 1);
  95. }
  96. for (; i < dimension * SOBOL_MATRIX_SIZE + 32+20; index64.y >>= 1, ++i)
  97. {
  98. result ^= _SobolMatricesBuffer[i] * (index64.y & 1);
  99. }
  100. return result;
  101. }
  102. uint GetMortonShuffledSampleIndex(uint index, uint pixelMortonIndex, uint mortonShuffleSeed, uint log2SamplesPerPixel)
  103. {
  104. uint mortonIndexShuffled = NestedUniformScrambleBase4(pixelMortonIndex, mortonShuffleSeed);
  105. uint sampleIndexForPixel = (mortonIndexShuffled << log2SamplesPerPixel) | index;
  106. return sampleIndexForPixel;
  107. }
  108. uint2 GetMortonShuffledSampleIndex64(uint index, uint pixelMortonIndex, uint mortonShuffleSeed, uint log2SamplesPerPixel)
  109. {
  110. uint mortonIndexShuffled = NestedUniformScrambleBase4(pixelMortonIndex, mortonShuffleSeed);
  111. uint2 sampleIndex64;
  112. sampleIndex64.x = (mortonIndexShuffled << log2SamplesPerPixel) | index;
  113. sampleIndex64.y = mortonIndexShuffled >> (32 - log2SamplesPerPixel);
  114. return sampleIndex64;
  115. }
  116. float GetSobolSample(uint index, int dimension)
  117. {
  118. uint result = SobolSampleUint(index, dimension, 20);
  119. return UintToFloat01(result);
  120. }
  121. float GetOwenScrambledSobolSample(uint sampleIndex, uint dim, uint valueScrambleSeed)
  122. {
  123. uint sobolUInt = SobolSampleUint(sampleIndex, dim, 20);
  124. uint result = NestedUniformOwenScramble(sobolUInt, valueScrambleSeed);
  125. return UintToFloat01(result);
  126. }
  127. float GetOwenScrambledZShuffledSobolSample(uint sampleIndex, uint dim, uint maxDim, uint pixelMortonCode, uint log2SamplesPerPixel)
  128. {
  129. const uint kSeedValueScramble = 0xab773au;
  130. uint mortonShuffleSeed = LowBiasHash32(dim, 0);
  131. uint valueScrambleSeed = LowBiasHash32(dim, kSeedValueScramble);
  132. #ifdef QRNG_GLOBAL_SOBOL_ENHANCED_TILING
  133. uint2 shuffledSampleIndex = GetMortonShuffledSampleIndex64(sampleIndex, pixelMortonCode, mortonShuffleSeed, log2SamplesPerPixel);
  134. uint sobolUInt = SobolSampleUint(shuffledSampleIndex, dim % maxDim);
  135. #else
  136. uint shuffledSampleIndex = GetMortonShuffledSampleIndex(sampleIndex, pixelMortonCode, mortonShuffleSeed, log2SamplesPerPixel);
  137. uint sobolUInt = SobolSampleUint(shuffledSampleIndex, dim % maxDim, 32);
  138. #endif
  139. uint result = NestedUniformOwenScramble(sobolUInt, valueScrambleSeed);
  140. return UintToFloat01(result);
  141. }
  142. #endif // UNITY_SOBOL_SAMPLING_INCLUDED