DirectionalLightShadow.azsli 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #ifndef ENABLE_SHADOWS
  10. #define ENABLE_SHADOWS 1
  11. #endif
  12. #if ENABLE_SHADOWS
  13. #ifndef ENABLE_FULLSCREEN_SHADOW
  14. #define ENABLE_FULLSCREEN_SHADOW 1
  15. #endif
  16. #include <scenesrg_all.srgi>
  17. #include <viewsrg_all.srgi>
  18. #include <Atom/RPI/Math.azsli>
  19. #include "Shadow.azsli"
  20. #include "ShadowmapAtlasLib.azsli"
  21. #include "BicubicPcfFilters.azsli"
  22. #include "ReceiverPlaneDepthBias.azsli"
  23. #include "NormalOffsetShadows.azsli"
  24. #include "DirectionalLightShadowCalculator.azsli"
  25. // This matchs ShadowFilterMethod in ShadowConstants.h
  26. option ShadowFilterMethod o_directional_shadow_filtering_method = ShadowFilterMethod::None;
  27. option bool o_directional_shadow_receiver_plane_bias_enable = true;
  28. option bool o_blend_between_cascades_enable = false;
  29. // DirectionalLightShadow calculates lit ratio for a directional light.
  30. class DirectionalLightShadow
  31. {
  32. static bool UseFullscreenShadows();
  33. //! Calculates visibility ratio of the surface from the light origin. Should be called from fragment shaders.
  34. //! Returns lit ratio from the light (1.0 is fully visible, 0.0 is fully shadowed).
  35. static real GetVisibility(uint lightIndex, float3 worldPos, real3 normalVector, float4 screenUv);
  36. static float2 GetVisibilityThickTransmission(uint lightIndex, real3 worldPos, real3 normalVector, float4 screenUv);
  37. static float2 GetVisibilityThinTransmission(uint lightIndex, real3 worldPos, real3 normalVector, float4 screenUv, real shrinkFactor);
  38. static DirectionalShadowCalculator MakeShadowCalculator(uint lightIndex, float3 worldPos, real3 normalVector);
  39. //! This alters the input color to visualize which cascade is being used
  40. //! and whether PCF is used as a fallback in ESM+PCF mode or not.
  41. static real3 AddDebugColoring(real3 color, uint lightIndex, real3 worldPos, real3 normalVector);
  42. };
  43. bool DirectionalLightShadow::UseFullscreenShadows()
  44. {
  45. #if ENABLE_FULLSCREEN_SHADOW
  46. #if FORCE_OPAQUE
  47. return true;
  48. #else
  49. bool useFullscreenShadows = o_opacity_mode == OpacityMode::Opaque || o_opacity_mode == OpacityMode::Cutout;
  50. return useFullscreenShadows;
  51. #endif
  52. #else
  53. return false;
  54. #endif
  55. }
  56. DirectionalShadowCalculator DirectionalLightShadow::MakeShadowCalculator(uint lightIndex, float3 worldPos, real3 normalVector)
  57. {
  58. DirectionalShadowCalculator calc;
  59. calc.SetBlendBetweenCascadesEnable(o_blend_between_cascades_enable);
  60. calc.SetShadowmaps(PassSrg::m_directionalLightShadowmap, PassSrg::m_directionalLightExponentialShadowmap);
  61. calc.SetReceiverShadowPlaneBiasEnable(o_directional_shadow_receiver_plane_bias_enable);
  62. calc.SetWorldNormal(normalVector);
  63. calc.SetLightIndex(lightIndex);
  64. calc.SetFilterMode(o_directional_shadow_filtering_method);
  65. calc.SetFilteringSampleCount(o_directional_shadow_filtering_sample_count);
  66. calc.SetWorldPos(worldPos);
  67. return calc;
  68. }
  69. float2 DirectionalLightShadow::GetVisibilityThickTransmission(uint lightIndex, real3 worldPos, real3 normalVector, float4 screenUv)
  70. {
  71. float visibility;
  72. DirectionalShadowCalculator calc = MakeShadowCalculator(lightIndex, worldPos, normalVector);
  73. if (UseFullscreenShadows())
  74. {
  75. visibility = PassSrg::m_fullscreenShadow.Load(int3(screenUv.xy, 0)).x;
  76. // Compute shadow coords for call to GetThickness below
  77. calc.ComputeShadowCoords();
  78. }
  79. else
  80. {
  81. visibility = calc.GetVisibility();
  82. }
  83. float thickness = calc.GetThickness();
  84. return float2(visibility, thickness);
  85. }
  86. float2 DirectionalLightShadow::GetVisibilityThinTransmission(uint lightIndex, real3 worldPos, real3 normalVector, float4 screenUv, real shrinkFactor)
  87. {
  88. float visibility;
  89. DirectionalShadowCalculator calc = MakeShadowCalculator(lightIndex, worldPos, normalVector);
  90. if (UseFullscreenShadows())
  91. {
  92. visibility = PassSrg::m_fullscreenShadow.Load(int3(screenUv.xy, 0)).x;
  93. }
  94. else
  95. {
  96. visibility = calc.GetVisibility();
  97. }
  98. // Apply transmission shrink factor for thin transmission materials and recalculate shadow coords
  99. // This way the shrink factor only gets applied to the thickness/transmission factor and not to the default shadows
  100. calc.SetWorldPos(worldPos - shrinkFactor * normalVector);
  101. calc.ComputeShadowCoords();
  102. float thickness = calc.GetThickness();
  103. return float2(visibility, thickness);
  104. }
  105. real DirectionalLightShadow::GetVisibility(uint lightIndex, float3 worldPos, real3 normalVector, float4 screenUv)
  106. {
  107. if (UseFullscreenShadows())
  108. {
  109. return real(PassSrg::m_fullscreenShadow.Load(int3(screenUv.xy, 0)).x);
  110. }
  111. else
  112. {
  113. DirectionalShadowCalculator calc = MakeShadowCalculator(lightIndex, worldPos, normalVector);
  114. return calc.GetVisibility();
  115. }
  116. }
  117. real3 DirectionalLightShadow::AddDebugColoring(real3 color, uint lightIndex, real3 worldPos, real3 normalVector)
  118. {
  119. if ((ViewSrg::m_directionalLightShadows[lightIndex].m_debugFlags &
  120. ViewSrg::DirectionalLightShadowDebugColoringBitMask) == 0)
  121. {
  122. return color;
  123. }
  124. const uint cascadeCount = ViewSrg::m_directionalLightShadows[lightIndex].m_cascadeCount;
  125. DirectionalShadowCalculator calc = MakeShadowCalculator(lightIndex, worldPos, normalVector);
  126. calc.ComputeShadowCoords();
  127. if (calc.m_maxCascade < cascadeCount)
  128. {
  129. // Each cascade has an assigned color. Pixels that are a blend of cascades will blend the colors.
  130. static const real3 debuggingColors[ViewSrg::MaxCascadeCount] =
  131. {
  132. real3(1., 0., 0.),
  133. real3(0., 1., 0.),
  134. real3(0., 0., 1.),
  135. real3(1., 1., 0.)
  136. };
  137. real3 debugColor = real3(0.0, 0.0, 0.0);
  138. for (int i = calc.m_minCascade; i <= calc.m_maxCascade; ++i)
  139. {
  140. debugColor += debuggingColors[i];
  141. }
  142. debugColor *= real(rcp(calc.m_maxCascade - calc.m_minCascade + 1.0));
  143. color = color * 0.75 + debugColor * 0.25;
  144. }
  145. return color;
  146. }
  147. #endif // ENABLE_SHADOWS