ShadowProjectOmni.bsl 5.4 KB

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