ShadowProjectOmni.bsl 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include "$ENGINE$/GBufferInput.bslinc"
  2. #include "$ENGINE$/ShadowProjectionCommon.bslinc"
  3. technique ShadowProjectOmni
  4. {
  5. mixin GBufferInput;
  6. mixin ShadowProjectionCommon;
  7. variations
  8. {
  9. SHADOW_QUALITY = { 1, 2, 3, 4 };
  10. VIEWER_INSIDE_VOLUME = { true, false };
  11. NEEDS_TRANSFORM = { true, false };
  12. MSAA_COUNT = { 1, 2 };
  13. };
  14. blend
  15. {
  16. target
  17. {
  18. enabled = true;
  19. writemask = R;
  20. color = { one, one, max };
  21. };
  22. };
  23. #if VIEWER_INSIDE_VOLUME
  24. depth
  25. {
  26. read = false;
  27. write = false;
  28. };
  29. raster
  30. {
  31. cull = cw;
  32. };
  33. #else
  34. depth
  35. {
  36. write = false;
  37. };
  38. raster
  39. {
  40. cull = ccw;
  41. };
  42. #endif
  43. code
  44. {
  45. // Random samples on a disc of radius 2.5. Random values generated using low discrepancy
  46. // Hammersley sequence and then mapped to the disc.
  47. static const float2 discSamples4[4] =
  48. {
  49. float2(0, 0),
  50. float2(-1.25, 6.69872e-08),
  51. float2(4.73671e-08, 1.76777),
  52. float2(-1.74038e-07, -2.16506)
  53. };
  54. static const float2 discSamples12[12] =
  55. {
  56. float2(0, 0),
  57. float2(-0.721688, 3.86751e-08),
  58. float2(2.73474e-08, 1.02062),
  59. float2(-1.00481e-07, -1.25),
  60. float2(1.02062, 1.02062),
  61. float2(-1.14109, -1.14109),
  62. float2(-1.25, 1.25),
  63. float2(1.35015, -1.35015),
  64. float2(1.88586, 0.781149),
  65. float2(-2.00026, -0.828534),
  66. float2(-0.873351, 2.10846),
  67. float2(0.915979, -2.21137)
  68. };
  69. static const float2 discSamples32[32] =
  70. {
  71. float2(0, 0),
  72. float2(-0.441942, 2.36836e-08),
  73. float2(1.67468e-08, 0.625),
  74. float2(-6.15317e-08, -0.765466),
  75. float2(0.625, 0.625),
  76. float2(-0.698771, -0.698771),
  77. float2(-0.765465, 0.765466),
  78. float2(0.826797, -0.826797),
  79. float2(1.15485, 0.478354),
  80. float2(-1.2249, -0.507371),
  81. float2(-0.534816, 1.29116),
  82. float2(0.56092, -1.35418),
  83. float2(0.585862, 1.4144),
  84. float2(-0.609785, -1.47215),
  85. float2(-1.52772, 0.632803),
  86. float2(1.58134, -0.655014),
  87. float2(1.7338, 0.344874),
  88. float2(-1.78716, -0.355488),
  89. float2(-0.365794, 1.83897),
  90. float2(0.375818, -1.88936),
  91. float2(1.09804, 1.64334),
  92. float2(-1.12516, -1.68392),
  93. float2(-1.72355, 1.15164),
  94. float2(1.76228, -1.17752),
  95. float2(1.80018, 1.20284),
  96. float2(-1.83731, -1.22765),
  97. float2(-1.25196, 1.87369),
  98. float2(1.27581, -1.90938),
  99. float2(0.456226, 2.2936),
  100. float2(-0.464301, -2.3342),
  101. float2(-2.3741, 0.472239),
  102. float2(2.41335, -0.480045)
  103. };
  104. TextureCube gShadowCubeTex;
  105. SamplerComparisonState gShadowCubeSampler;
  106. cbuffer Params
  107. {
  108. float4x4 gFaceVPMatrices[6];
  109. float4 gLightPosAndRadius;
  110. float gInvResolution;
  111. float gFadePercent;
  112. float gDepthBias;
  113. };
  114. // Returns occlusion where 1 = fully shadowed, 0 = not shadowed
  115. float cubemapPCF(float3 worldPos, float3 lightPos, float lightRadius)
  116. {
  117. float3 fromLight = worldPos - lightPos;
  118. float distToLight = length(fromLight);
  119. // No occlusion if outside radius
  120. if(distToLight > lightRadius)
  121. return 0.0f;
  122. float3 lightDir = fromLight / distToLight;
  123. float3 up = abs(lightDir.z) < 0.999f ? float3(0, 0, 1) : float3(1, 0, 0);
  124. float3 side = normalize(cross(up, lightDir));
  125. up = cross(lightDir, side);
  126. up *= gInvResolution;
  127. side *= gInvResolution;
  128. // Determine cube face to sample from
  129. float3 absFromLight = abs(fromLight);
  130. float maxComponent = max(absFromLight.x, max(absFromLight.y, absFromLight.z));
  131. int faceIdx = 0;
  132. if(maxComponent == absFromLight.x)
  133. faceIdx = fromLight.x > 0.0f ? 0 : 1;
  134. else if(maxComponent == absFromLight.z)
  135. faceIdx = fromLight.z > 0.0f ? 4 : 5;
  136. else
  137. faceIdx = fromLight.y > 0.0f ? 2 : 3;
  138. // Get position of the receiver in shadow space
  139. float4 shadowPos = mul(gFaceVPMatrices[faceIdx], float4(worldPos, 1));
  140. float receiverDepth = NDCZToDeviceZ(shadowPos.z / shadowPos.w);
  141. float shadowBias = gDepthBias / shadowPos.w;
  142. float occlusion = 0.0f;
  143. #if SHADOW_QUALITY <= 1
  144. occlusion = gShadowCubeTex.SampleCmp(gShadowCubeSampler, lightDir, receiverDepth - shadowBias);
  145. #elif SHADOW_QUALITY == 2
  146. [unroll]
  147. for(int i = 0; i < 4; ++i)
  148. {
  149. float3 sampleDir = lightDir + side * discSamples4[i].x + up * discSamples4[i].y;
  150. occlusion += gShadowCubeTex.SampleCmp(gShadowCubeSampler, sampleDir, receiverDepth - shadowBias);
  151. }
  152. occlusion /= 4;
  153. #elif SHADOW_QUALITY == 3
  154. [unroll]
  155. for(int i = 0; i < 12; ++i)
  156. {
  157. float3 sampleDir = lightDir + side * discSamples12[i].x + up * discSamples12[i].y;
  158. occlusion += gShadowCubeTex.SampleCmp(gShadowCubeSampler, sampleDir, receiverDepth - shadowBias);
  159. }
  160. occlusion /= 12;
  161. #else
  162. [unroll]
  163. for(int i = 0; i < 32; ++i)
  164. {
  165. float3 sampleDir = lightDir + side * discSamples32[i].x + up * discSamples32[i].y;
  166. occlusion += gShadowCubeTex.SampleCmp(gShadowCubeSampler, sampleDir, receiverDepth - shadowBias);
  167. }
  168. occlusion /= 32;
  169. #endif
  170. return occlusion;
  171. }
  172. float4 fsmain(VStoFS input, uint sampleIdx : SV_SampleIndex) : SV_Target0
  173. {
  174. float2 ndcPos = input.clipSpacePos.xy / input.clipSpacePos.w;
  175. uint2 pixelPos = NDCToScreen(ndcPos);
  176. // Get depth & calculate world position
  177. #if MSAA_COUNT > 1
  178. float deviceZ = gDepthBufferTex.Load(pixelPos, sampleIdx).r;
  179. #else
  180. float deviceZ = gDepthBufferTex.Load(int3(pixelPos, 0)).r;
  181. #endif
  182. float depth = convertFromDeviceZ(deviceZ);
  183. float3 worldPos = NDCToWorld(ndcPos, depth);
  184. float occlusion = cubemapPCF(worldPos, gLightPosAndRadius.xyz, gLightPosAndRadius.w);
  185. occlusion *= gFadePercent;
  186. // Encode to get better precision in the blacks, similar to gamma correction but cheaper to execute
  187. return sqrt(occlusion);
  188. }
  189. };
  190. };