ReflectionGlobalFullscreen.azsl 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  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. // Specular IBL reflection pipeline:
  9. // Stencil -> BlendWeight -> GlobalFullscreen -> RenderOuter -> RenderInner -> Composite
  10. // ----------------
  11. //
  12. // This shader performs a fullscreen pass on stenciled pixels that require specular IBL.
  13. // It outputs some amount of the Global IBL cubemap as determined by the blend weight texture
  14. // from the previous pass. If the probes are going to write a total of >= 100% of local IBL
  15. // to this pixel then no Global IBL will be written since it is fully covered by probe IBL.
  16. // Note that this shader only considers pixels stenciled to non-probe space or probe outer
  17. // volumes (stencil value == UseSpecularIBLPass). Inner probe volumes never receive Global IBL.
  18. //
  19. // Additional notes:
  20. // - MSAA Input: The shader calculates the specular from the sub-pixels of the incoming textures
  21. // and box-filters the result.
  22. // - MSAA Output: Since this is a fullscreen pass the shader will write identical values to all
  23. // sub-pixel samples that pass the sub-pixel stencil test.
  24. // - An output of (0.0f, 0.0f, 0.0f) will be written if no global IBL will blend at this location.
  25. // This is necessary to clear the pixel since the probes additively write their specular values
  26. // in the following passes.
  27. #include <scenesrg_all.srgi>
  28. #include <viewsrg_all.srgi>
  29. #include <Atom/Features/PostProcessing/FullscreenVertexUtil.azsli>
  30. #include <Atom/Features/PostProcessing/FullscreenVertexInfo.azsli>
  31. #include <Atom/Features/PostProcessing/FullscreenPixelInfo.azsli>
  32. #include <Atom/Features/MatrixUtility.azsli>
  33. #include <Atom/Features/PBR/LightingUtils.azsli>
  34. #include <Atom/Features/PBR/Microfacet/Fresnel.azsli>
  35. ShaderResourceGroup PassSrg : SRG_PerPass
  36. {
  37. Texture2DMS<float> m_depth;
  38. Texture2DMS<float4> m_normal; // RGB10 = EncodeNormalSignedOctahedron(worldNormal), A2 = multiScatterCompensationEnabled
  39. Texture2DMS<float4> m_specularF0; // RGB8 = SpecularF0, A8 = Roughness
  40. Texture2DMS<float4> m_albedo; // RGB8 = Albedo, A = specularOcclusion
  41. Texture2DMS<float> m_blendWeight;
  42. Texture2D<float2> m_brdfMap;
  43. Sampler LinearSampler
  44. {
  45. MinFilter = Linear;
  46. MagFilter = Linear;
  47. MipFilter = Linear;
  48. AddressU = Clamp;
  49. AddressV = Clamp;
  50. AddressW = Clamp;
  51. };
  52. }
  53. #include "ReflectionCommon.azsli"
  54. // Vertex Shader
  55. VSOutput MainVS(VSInput input)
  56. {
  57. VSOutput OUT;
  58. float4 posTex = GetVertexPositionAndTexCoords(input.m_vertexID);
  59. OUT.m_texCoord = float2(posTex.z, posTex.w);
  60. OUT.m_position = float4(posTex.x, posTex.y, 0.0, 1.0);
  61. return OUT;
  62. }
  63. // Pixel Shader
  64. PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex)
  65. {
  66. float4 encodedNormal = PassSrg::m_normal.Load(IN.m_position.xy, sampleIndex);
  67. float3 normal = DecodeNormalSignedOctahedron(encodedNormal.rgb);
  68. bool enableIBL = DecodeUnorm2BitFlag1(encodedNormal.a);
  69. if (!enableIBL)
  70. {
  71. PSOutput OUT;
  72. OUT.m_color = float4(0.0f, 0.0f, 0.0f, 1.0f);
  73. return OUT;
  74. }
  75. bool multiScatterCompensationEnabled = DecodeUnorm2BitFlag2(encodedNormal.a);
  76. float4 albedo = PassSrg::m_albedo.Load(IN.m_position.xy, sampleIndex);
  77. float specularOcclusion = albedo.a;
  78. // reconstruct world space position from the depth at this location in screenspace
  79. uint2 dimensions;
  80. uint samples;
  81. PassSrg::m_depth.GetDimensions(dimensions.x, dimensions.y, samples);
  82. float depth = PassSrg::m_depth.Load(IN.m_position.xy, sampleIndex).r;
  83. float3 positionWS = ReconstructWorldPositionFromDepth(IN.m_position.xy, depth, dimensions, sampleIndex).xyz;
  84. // sample blend weight at this location
  85. float blendWeight = PassSrg::m_blendWeight.Load(IN.m_position.xy, sampleIndex).r;
  86. // blend weight for this pixel is the remainder of total blends for local probes
  87. // E.g., 0.2f probes = 0.8f global, 0.0f probes = 1.0f global, >1.0f probes = 0.0f global
  88. blendWeight = 1.0f - min(blendWeight, 1.0f);
  89. float3 specularF0 = PassSrg::m_specularF0.Load(IN.m_position.xy, sampleIndex).rgb;
  90. float roughness = PassSrg::m_specularF0.Load(IN.m_position.xy, sampleIndex).a;
  91. float3 dirToCamera = normalize(ViewSrg::m_worldPosition.xyz - positionWS);
  92. float3 reflectDir = reflect(-dirToCamera, normal);
  93. reflectDir = MultiplyVectorQuaternion(reflectDir, SceneSrg::m_iblOrientation);
  94. float3 globalSpecular = SceneSrg::m_specularEnvMap.SampleLevel(SceneSrg::m_samplerEnv, GetCubemapCoords(reflectDir), GetRoughnessMip(roughness)).rgb;
  95. float NdotV = saturate(dot(normal, dirToCamera));
  96. NdotV = max(NdotV, 0.01f); // [GFX TODO][ATOM-4466] This is a current band-aid for specular noise at grazing angles.
  97. float2 brdf = PassSrg::m_brdfMap.Sample(PassSrg::LinearSampler, GetBRDFTexCoords(roughness, NdotV)).rg;
  98. float3 multiScatterCompensation = GetMultiScatterCompensation(specularF0, brdf, multiScatterCompensationEnabled);
  99. float3 specular = blendWeight * globalSpecular * multiScatterCompensation * (specularF0 * brdf.x + brdf.y);
  100. // apply exposure setting
  101. specular *= pow(2.0, SceneSrg::m_iblExposure);
  102. // maybe attenuate the specular
  103. specular *= specularOcclusion;
  104. PSOutput OUT;
  105. OUT.m_color = float4(specular, 1.0f);
  106. return OUT;
  107. }