AoRenderCS.hlsli 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. //
  2. // Copyright (c) Microsoft. All rights reserved.
  3. // This code is licensed under the MIT License (MIT).
  4. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  5. // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  6. // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  7. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  8. //
  9. // Developed by Minigraph
  10. //
  11. // Author: James Stanard
  12. //
  13. #include "SSAORS.hlsli"
  14. #ifndef INTERLEAVE_RESULT
  15. #define WIDE_SAMPLING 1
  16. #endif
  17. #ifdef INTERLEAVE_RESULT
  18. Texture2DArray<float> DepthTex : register(t0);
  19. #else
  20. Texture2D<float> DepthTex : register(t0);
  21. #endif
  22. RWTexture2D<float> Occlusion : register(u0);
  23. SamplerState LinearBorderSampler : register(s1);
  24. cbuffer ConstantBuffer_x : register(b1)
  25. {
  26. float4 gInvThicknessTable[3];
  27. float4 gSampleWeightTable[3];
  28. float2 gInvSliceDimension;
  29. float gRejectFadeoff;
  30. float gRcpAccentuation;
  31. }
  32. #if WIDE_SAMPLING
  33. // 32x32 cache size: the 16x16 in the center forms the area of focus with the 8-pixel perimeter used for wide gathering.
  34. #define TILE_DIM 32
  35. #define THREAD_COUNT_X 16
  36. #define THREAD_COUNT_Y 16
  37. #else
  38. // 16x16 cache size: the 8x8 in the center forms the area of focus with the 4-pixel perimeter used for gathering.
  39. #define TILE_DIM 16
  40. #define THREAD_COUNT_X 8
  41. #define THREAD_COUNT_Y 8
  42. #endif
  43. groupshared float DepthSamples[TILE_DIM * TILE_DIM];
  44. float TestSamplePair( float frontDepth, float invRange, uint base, int offset )
  45. {
  46. // "Disocclusion" measures the penetration distance of the depth sample within the sphere.
  47. // Disocclusion < 0 (full occlusion) -> the sample fell in front of the sphere
  48. // Disocclusion > 1 (no occlusion) -> the sample fell behind the sphere
  49. float disocclusion1 = DepthSamples[base + offset] * invRange - frontDepth;
  50. float disocclusion2 = DepthSamples[base - offset] * invRange - frontDepth;
  51. float pseudoDisocclusion1 = saturate(gRejectFadeoff * disocclusion1);
  52. float pseudoDisocclusion2 = saturate(gRejectFadeoff * disocclusion2);
  53. return
  54. clamp(disocclusion1, pseudoDisocclusion2, 1.0) +
  55. clamp(disocclusion2, pseudoDisocclusion1, 1.0) -
  56. pseudoDisocclusion1 * pseudoDisocclusion2;
  57. }
  58. float TestSamples( uint centerIdx, uint x, uint y, float invDepth, float invThickness )
  59. {
  60. #if WIDE_SAMPLING
  61. x <<= 1;
  62. y <<= 1;
  63. #endif
  64. float invRange = invThickness * invDepth;
  65. float frontDepth = invThickness - 0.5;
  66. if (y == 0)
  67. {
  68. // Axial
  69. return 0.5 * (
  70. TestSamplePair(frontDepth, invRange, centerIdx, x) +
  71. TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM));
  72. }
  73. else if (x == y)
  74. {
  75. // Diagonal
  76. return 0.5 * (
  77. TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM - x) +
  78. TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM + x));
  79. }
  80. else
  81. {
  82. // L-Shaped
  83. return 0.25 * (
  84. TestSamplePair(frontDepth, invRange, centerIdx, y * TILE_DIM + x) +
  85. TestSamplePair(frontDepth, invRange, centerIdx, y * TILE_DIM - x) +
  86. TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM + y) +
  87. TestSamplePair(frontDepth, invRange, centerIdx, x * TILE_DIM - y));
  88. }
  89. }
  90. [RootSignature(SSAO_RootSig)]
  91. #if WIDE_SAMPLING
  92. [numthreads( 16, 16, 1 )]
  93. #else
  94. [numthreads( 8, 8, 1 )]
  95. #endif
  96. void main( uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex, uint3 GTid : SV_GroupThreadID, uint3 DTid : SV_DispatchThreadID )
  97. {
  98. #if WIDE_SAMPLING
  99. float2 QuadCenterUV = (DTid.xy + GTid.xy - 7) * gInvSliceDimension;
  100. #else
  101. float2 QuadCenterUV = (DTid.xy + GTid.xy - 3) * gInvSliceDimension;
  102. #endif
  103. // Fetch four depths and store them in LDS
  104. #ifdef INTERLEAVE_RESULT
  105. float4 depths = DepthTex.Gather(LinearBorderSampler, float3(QuadCenterUV, DTid.z));
  106. #else
  107. float4 depths = DepthTex.Gather(LinearBorderSampler, QuadCenterUV);
  108. #endif
  109. int destIdx = GTid.x * 2 + GTid.y * 2 * TILE_DIM;
  110. DepthSamples[destIdx] = depths.w;
  111. DepthSamples[destIdx + 1] = depths.z;
  112. DepthSamples[destIdx + TILE_DIM] = depths.x;
  113. DepthSamples[destIdx + TILE_DIM + 1] = depths.y;
  114. GroupMemoryBarrierWithGroupSync();
  115. #if WIDE_SAMPLING
  116. uint thisIdx = GTid.x + GTid.y * TILE_DIM + 8 * TILE_DIM + 8;
  117. #else
  118. uint thisIdx = GTid.x + GTid.y * TILE_DIM + 4 * TILE_DIM + 4;
  119. #endif
  120. const float invThisDepth = 1.0 / DepthSamples[thisIdx];
  121. float ao = 0.0;
  122. //#define SAMPLE_EXHAUSTIVELY
  123. #ifdef SAMPLE_EXHAUSTIVELY
  124. // 68 samples: sample all cells in *within* a circular radius of 5
  125. ao += gSampleWeightTable[0].x * TestSamples(thisIdx, 1, 0, invThisDepth, gInvThicknessTable[0].x);
  126. ao += gSampleWeightTable[0].y * TestSamples(thisIdx, 2, 0, invThisDepth, gInvThicknessTable[0].y);
  127. ao += gSampleWeightTable[0].z * TestSamples(thisIdx, 3, 0, invThisDepth, gInvThicknessTable[0].z);
  128. ao += gSampleWeightTable[0].w * TestSamples(thisIdx, 4, 0, invThisDepth, gInvThicknessTable[0].w);
  129. ao += gSampleWeightTable[1].x * TestSamples(thisIdx, 1, 1, invThisDepth, gInvThicknessTable[1].x);
  130. ao += gSampleWeightTable[2].x * TestSamples(thisIdx, 2, 2, invThisDepth, gInvThicknessTable[2].x);
  131. ao += gSampleWeightTable[2].w * TestSamples(thisIdx, 3, 3, invThisDepth, gInvThicknessTable[2].w);
  132. ao += gSampleWeightTable[1].y * TestSamples(thisIdx, 1, 2, invThisDepth, gInvThicknessTable[1].y);
  133. ao += gSampleWeightTable[1].z * TestSamples(thisIdx, 1, 3, invThisDepth, gInvThicknessTable[1].z);
  134. ao += gSampleWeightTable[1].w * TestSamples(thisIdx, 1, 4, invThisDepth, gInvThicknessTable[1].w);
  135. ao += gSampleWeightTable[2].y * TestSamples(thisIdx, 2, 3, invThisDepth, gInvThicknessTable[2].y);
  136. ao += gSampleWeightTable[2].z * TestSamples(thisIdx, 2, 4, invThisDepth, gInvThicknessTable[2].z);
  137. #else // SAMPLE_CHECKER
  138. // 36 samples: sample every-other cell in a checker board pattern
  139. ao += gSampleWeightTable[0].y * TestSamples(thisIdx, 2, 0, invThisDepth, gInvThicknessTable[0].y);
  140. ao += gSampleWeightTable[0].w * TestSamples(thisIdx, 4, 0, invThisDepth, gInvThicknessTable[0].w);
  141. ao += gSampleWeightTable[1].x * TestSamples(thisIdx, 1, 1, invThisDepth, gInvThicknessTable[1].x);
  142. ao += gSampleWeightTable[2].x * TestSamples(thisIdx, 2, 2, invThisDepth, gInvThicknessTable[2].x);
  143. ao += gSampleWeightTable[2].w * TestSamples(thisIdx, 3, 3, invThisDepth, gInvThicknessTable[2].w);
  144. ao += gSampleWeightTable[1].z * TestSamples(thisIdx, 1, 3, invThisDepth, gInvThicknessTable[1].z);
  145. ao += gSampleWeightTable[2].z * TestSamples(thisIdx, 2, 4, invThisDepth, gInvThicknessTable[2].z);
  146. #endif
  147. #ifdef INTERLEAVE_RESULT
  148. uint2 OutPixel = DTid.xy << 2 | uint2(DTid.z & 3, DTid.z >> 2);
  149. #else
  150. uint2 OutPixel = DTid.xy;
  151. #endif
  152. Occlusion[OutPixel] = ao * gRcpAccentuation;
  153. }