AsyncComputeShadow.azsl 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. #include <Atom/Features/SrgSemantics.azsli>
  9. #include <viewsrg.srgi>
  10. ShaderResourceGroup ShadowSrg : SRG_PerObject
  11. {
  12. row_major float4x4 m_worldMatrix;
  13. row_major float4x4 m_lightViewProjectionMatrix;
  14. float4 m_lightPosition;
  15. float4 m_ambientColor;
  16. float4 m_diffuseColor;
  17. Texture2D m_depthMapTexture;
  18. SamplerComparisonState m_shadowSampler
  19. {
  20. MagFilter = Linear;
  21. MinFilter = Linear;
  22. MipFilter = Point;
  23. ComparisonFunc = Less;
  24. MaxAnisotropy = 16;
  25. ReductionType = Comparison;
  26. };
  27. }
  28. struct VSInput
  29. {
  30. float3 m_position : POSITION;
  31. float3 m_normal: NORMAL;
  32. };
  33. struct VSOutput
  34. {
  35. float4 m_position : SV_Position;
  36. float3 m_normal: NORMAL;
  37. float4 m_lightViewPosition : TEXCOORD1;
  38. float3 m_worldPosition : TEXCOORD2;
  39. };
  40. VSOutput MainVS(VSInput vsInput)
  41. {
  42. VSOutput OUT;
  43. OUT.m_worldPosition = mul(ShadowSrg::m_worldMatrix, float4(vsInput.m_position, 1.0)).xyz;
  44. OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(OUT.m_worldPosition, 1.0));
  45. OUT.m_lightViewPosition = mul(ShadowSrg::m_lightViewProjectionMatrix, float4(OUT.m_worldPosition, 1.0));
  46. float4 normalsToWorld = mul(ShadowSrg::m_worldMatrix, float4(vsInput.m_normal, 0.0));
  47. OUT.m_normal = normalsToWorld.xyz;
  48. OUT.m_normal = normalize(OUT.m_normal);
  49. return OUT;
  50. }
  51. struct PSOutput
  52. {
  53. float4 m_color : SV_Target0;
  54. };
  55. //--------------------------------------------------------------------------------------------------
  56. // Computes shadows using a 5x5 kernel, but optimized to 9-taps using bilinear fetches.
  57. //
  58. // https://vec3.ca/bicubic-filtering-in-fewer-taps/
  59. //--------------------------------------------------------------------------------------------------
  60. float ShadowResolve_5x5PCF(const Texture2D shadowMap, const float3 shadowPos, const float shadowMapSize, const SamplerComparisonState samplerState)
  61. {
  62. const float invShadowMapSize = 1.0 / shadowMapSize;
  63. // Compute the shadow map UV and fractionals.
  64. float2 shadowScaled = shadowPos.xy * shadowMapSize + float2(0.5, 0.5);
  65. float2 shadowUv = floor(shadowScaled);
  66. float2 st = shadowScaled - shadowUv;
  67. shadowUv = (shadowUv - float2(0.5, 0.5)) * invShadowMapSize;
  68. // Compute the offsets and weights for the 9 bilinear taps.
  69. float2 uvw0 = 4.0 - 3.0 * st;
  70. float2 uvw1 = 7.0;
  71. float2 uvw2 = 1.0 + 3.0 * st;
  72. float2 vUV0 = ((3.0 - 2.0 * st) / uvw0) - 2.0;
  73. float2 vUV1 = (3.0 + st) / uvw1;
  74. float2 vUV2 = (st / uvw2) + 2.0;
  75. // Accumulate the shadow results and return the resolve value.
  76. float shadowResult;
  77. shadowResult = uvw0.x * uvw0.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV0.x, vUV0.y) * invShadowMapSize, shadowPos.z);
  78. shadowResult += uvw1.x * uvw0.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV1.x, vUV0.y) * invShadowMapSize, shadowPos.z);
  79. shadowResult += uvw2.x * uvw0.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV2.x, vUV0.y) * invShadowMapSize, shadowPos.z);
  80. shadowResult += uvw0.x * uvw1.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV0.x, vUV1.y) * invShadowMapSize, shadowPos.z);
  81. shadowResult += uvw1.x * uvw1.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV1.x, vUV1.y) * invShadowMapSize, shadowPos.z);
  82. shadowResult += uvw2.x * uvw1.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV2.x, vUV1.y) * invShadowMapSize, shadowPos.z);
  83. shadowResult += uvw0.x * uvw2.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV0.x, vUV2.y) * invShadowMapSize, shadowPos.z);
  84. shadowResult += uvw1.x * uvw2.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV1.x, vUV2.y) * invShadowMapSize, shadowPos.z);
  85. shadowResult += uvw2.x * uvw2.y * shadowMap.SampleCmpLevelZero(samplerState, shadowUv + float2(vUV2.x, vUV2.y) * invShadowMapSize, shadowPos.z);
  86. shadowResult /= 144.0;
  87. return shadowResult * shadowResult;
  88. }
  89. float GetShadowMapDimensions()
  90. {
  91. float shadowMapWidth, shadowMapHeight;
  92. ShadowSrg::m_depthMapTexture.GetDimensions(shadowMapWidth, shadowMapHeight);
  93. return shadowMapWidth;
  94. }
  95. PSOutput MainPS(VSOutput vsOutput)
  96. {
  97. PSOutput OUT;
  98. float bias = 0.001f;
  99. float shadowMask;
  100. float lightIntensity;
  101. float3 projectTexCoord;
  102. float3 lightDirection;
  103. OUT.m_color = ShadowSrg::m_ambientColor;
  104. lightDirection = ShadowSrg::m_lightPosition.xyz - vsOutput.m_worldPosition;
  105. lightDirection = normalize(lightDirection);
  106. projectTexCoord.xyz = vsOutput.m_lightViewPosition.xyz / vsOutput.m_lightViewPosition.w;
  107. projectTexCoord.xy = (projectTexCoord.xy / float2(2.0f, -2.0f)) + 0.5f;
  108. projectTexCoord.z -= bias;
  109. shadowMask = ShadowResolve_5x5PCF(ShadowSrg::m_depthMapTexture, projectTexCoord, GetShadowMapDimensions(), ShadowSrg::m_shadowSampler);
  110. lightIntensity = shadowMask * saturate(dot(normalize(vsOutput.m_normal), lightDirection));
  111. OUT.m_color += (ShadowSrg::m_diffuseColor * lightIntensity);
  112. OUT.m_color = saturate(OUT.m_color);
  113. return OUT;
  114. }