SkyBoxSubpass.azsl 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. // --- Static Options Available ---
  9. // SKYBOX_TWO_OUTPUTS - Skybox renders to two rendertargets instead of one (SkyBox_TwoOutputs.pass writes to specular and reflection targets)
  10. //#include <Atom/Features/Pipeline/Forward/ForwardPassSrg.azsli> // GALIB
  11. #include <Atom/Features/ColorManagement/TransformColor.azsli>
  12. #include <Atom/Features/PostProcessing/FullscreenVertexUtil.azsli>
  13. #include <Atom/Features/PostProcessing/Tonemap.azsli>
  14. #include <Atom/Features/MatrixUtility.azsli>
  15. #include <Atom/Features/ShaderQualityOptions.azsli>
  16. #include <scenesrg.srgi>
  17. #include <viewsrg.srgi>
  18. #ifndef ENABLE_PHYSICAL_SKY
  19. #define ENABLE_PHYSICAL_SKY 1
  20. #endif
  21. #ifndef ENABLE_MERGE_FILMIC_TONEMAP
  22. #define ENABLE_MERGE_FILMIC_TONEMAP 0
  23. #endif
  24. ShaderResourceGroup PassSrg : SRG_PerPass
  25. {
  26. [[input_attachment_index(0)]]
  27. SubpassInput m_depthInput;
  28. // Required for sampling the skybox texture.
  29. Sampler LinearSampler
  30. {
  31. MinFilter = Linear;
  32. MagFilter = Linear;
  33. MipFilter = Linear;
  34. AddressU = Clamp;
  35. AddressV = Clamp;
  36. AddressW = Clamp;
  37. };
  38. }
  39. struct VSInput
  40. {
  41. uint m_vertexID : SV_VertexID;
  42. };
  43. struct VSOutput
  44. {
  45. float4 m_position : SV_Position;
  46. float3 m_cubemapCoord : TEXCOORD0;
  47. };
  48. // The Hosek-Wilkie version of Perez formula
  49. // Parameters defination can be found in SkyBoxSystem.h
  50. // https://cgg.mff.cuni.cz/projects/SkylightModelling/HosekWilkie_SkylightModel_SIGGRAPH2012_Preprint_lowres.pdf
  51. float3 HosekWilkie(float cosGamma, float gamma, float cosTheta)
  52. {
  53. float3 A = SceneSrg::m_physicalSkyData.m_physicalSkyParameterA.xyz;
  54. float3 B = SceneSrg::m_physicalSkyData.m_physicalSkyParameterB.xyz;
  55. float3 C = SceneSrg::m_physicalSkyData.m_physicalSkyParameterC.xyz;
  56. float3 D = SceneSrg::m_physicalSkyData.m_physicalSkyParameterD.xyz;
  57. float3 E = SceneSrg::m_physicalSkyData.m_physicalSkyParameterE.xyz;
  58. float3 F = SceneSrg::m_physicalSkyData.m_physicalSkyParameterF.xyz;
  59. float3 G = SceneSrg::m_physicalSkyData.m_physicalSkyParameterG.xyz;
  60. float3 H = SceneSrg::m_physicalSkyData.m_physicalSkyParameterH.xyz;
  61. float3 I = SceneSrg::m_physicalSkyData.m_physicalSkyParameterI.xyz;
  62. float3 chi = (1 + cosGamma * cosGamma) / pow(1.0 + H * H - 2.0 * cosGamma * H, float3(1.5, 1.5, 1.5));
  63. return (1.0 + A * exp(B / (cosTheta + 0.01))) * (C + D * exp(E * gamma) + F * (cosGamma * cosGamma) + G * chi + I * sqrt(cosTheta));
  64. }
  65. VSOutput MainVS(VSInput input)
  66. {
  67. VSOutput OUT;
  68. float4 posTex = GetVertexPositionAndTexCoords(input.m_vertexID);
  69. OUT.m_position = float4(posTex.x, posTex.y, 0.0, 1.0);
  70. // camera transform matrix without translation
  71. float4x4 viewToWorldNoTranslation = ViewSrg::m_viewMatrixInverse;
  72. viewToWorldNoTranslation[0][3] = 0.0;
  73. viewToWorldNoTranslation[1][3] = 0.0;
  74. viewToWorldNoTranslation[2][3] = 0.0;
  75. viewToWorldNoTranslation[3][3] = 1.0;
  76. float4x4 skyboxMatrix = mul(viewToWorldNoTranslation, ViewSrg::m_projectionMatrixInverse);
  77. float usePhysicalSky = (float)SceneSrg::m_physicalSky;
  78. // Workaround for Qualcomm bug. This is the same as:
  79. // if(!SceneSrg::m_physicalSky)
  80. // skyboxMatrix = mul(SceneSrg::m_cubemapRotationMatrix, skyboxMatrix);
  81. skyboxMatrix = (mul(SceneSrg::m_cubemapRotationMatrix, skyboxMatrix) * (1.0 - usePhysicalSky)) + (skyboxMatrix * usePhysicalSky);
  82. // calculate cubemap coordinate
  83. float4 clipPosition = float4(posTex.x, posTex.y, 1.0, 1.0);
  84. float4 worldPosition = mul(skyboxMatrix, clipPosition);
  85. OUT.m_cubemapCoord = worldPosition.xyz / worldPosition.w;
  86. return OUT;
  87. }
  88. float3 GetCubemapCoords(float3 original)
  89. {
  90. // Environment cubemaps created by IBL Baker have to be rotated to be right-side-up
  91. return float3(-original.x, original.z, -original.y);
  92. }
  93. struct PSOutput
  94. {
  95. float4 m_specular : SV_Target0;
  96. #ifdef SKYBOX_TWO_OUTPUTS
  97. float4 m_reflection : SV_Target1;
  98. #endif
  99. };
  100. PSOutput MainPS(VSOutput input)
  101. {
  102. PSOutput OUT;
  103. if(!SceneSrg::m_enable)
  104. {
  105. discard;
  106. }
  107. int3 loadPos = int3(input.m_position.x, input.m_position.y, 0);
  108. const float zDepth = PassSrg::m_depthInput.SubpassLoad(loadPos).x;
  109. if (zDepth > 0.0)
  110. {
  111. //TODO: discard or clip(-1)?
  112. // In reverse depth, any value bigger than 0.0 means there's something already rendered here.
  113. // Because the skybox only renders in empty space, we skip this pixel.
  114. discard;
  115. return OUT;
  116. }
  117. real3 color = real3(0.5,0.5,0.5);
  118. #if ENABLE_PHYSICAL_SKY
  119. if(SceneSrg::m_physicalSky)
  120. {
  121. if(input.m_cubemapCoord.z >= 0.0)
  122. {
  123. // Default sun direction should be in +Y direction, so sun position should be in -Y
  124. input.m_cubemapCoord.y = -input.m_cubemapCoord.y;
  125. // Atom is Z-up, but the value is calculated in Y-up
  126. float3 worldPosition = normalize(input.m_cubemapCoord.yzx);
  127. // Theta is the angle between viewing direction and the zenith
  128. float cosTheta = worldPosition.y;
  129. // Gamma is the angle between viewing direction and the sun
  130. float cosGamma = dot(worldPosition, SceneSrg::m_physicalSkyData.m_physicalSkySunDirection.xyz);
  131. float gamma = acos(cosGamma);
  132. float3 sunParameters = SceneSrg::m_physicalSkyData.m_physicalSkySunParameters.xyz;
  133. // if gamma is smaller then anular diameter of the sun
  134. if(cosGamma > sunParameters.z)
  135. {
  136. // Render Sun
  137. // m_physicalSkyAndSunIntensity.y is the sun intensity assigned by user
  138. color = SceneSrg::m_physicalSkyData.m_physicalSkySunRGB.xyz * SceneSrg::m_physicalSkyData.m_physicalSkyAndSunIntensity.y * PassSrg::m_sunIntensityMultiplier;
  139. }
  140. else
  141. {
  142. // Render Sky
  143. // m_physicalSkyParameterZ is the sky color value at zenith
  144. // m_physicalSkyAndSunIntensity.x is the sky intensity assigned by user
  145. float3 Z = SceneSrg::m_physicalSkyData.m_physicalSkyParameterZ.xyz;
  146. float3 srgbColor = Z * HosekWilkie(cosGamma, gamma, cosTheta) * SceneSrg::m_physicalSkyData.m_physicalSkyAndSunIntensity.x;
  147. color = TransformColor(srgbColor, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
  148. }
  149. }
  150. if (SceneSrg::m_fogEnable)
  151. {
  152. if (input.m_cubemapCoord.z >= 0.0 && input.m_cubemapCoord.z <= SceneSrg::m_fogTopHeight)
  153. {
  154. color = lerp(SceneSrg::m_fogColor.rgb, color, input.m_cubemapCoord.z > 0.0 ? input.m_cubemapCoord.z/SceneSrg::m_fogTopHeight : 0.0);
  155. }
  156. else if (input.m_cubemapCoord.z < 0.0 && input.m_cubemapCoord.z >= -SceneSrg::m_fogBottomHeight)
  157. {
  158. color = SceneSrg::m_fogColor.rgb;
  159. }
  160. }
  161. }
  162. else
  163. #endif
  164. {
  165. color = real3(SceneSrg::m_skyboxCubemap.Sample(PassSrg::LinearSampler, GetCubemapCoords(input.m_cubemapCoord)).rgb);
  166. //No need to go to acescg if the tonemap will be applied right away.
  167. #if !ENABLE_MERGE_FILMIC_TONEMAP
  168. color = TransformColor(color, ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
  169. #endif
  170. // apply the exposure for HDRi texture
  171. real exposureFactor = pow(2.0, real(SceneSrg::m_cubemapExposure));
  172. color *= exposureFactor;
  173. }
  174. // Clamp lower bounds of sky to prevent zero or negative values, which can leads to NaNs in other shaders like SMAA
  175. color = max(0.000001, color);
  176. #if ENABLE_MERGE_FILMIC_TONEMAP
  177. // Apply manual exposure compensation
  178. color = ApplyManualExposure(color, real(ViewSrg::GetExposureValueCompensation()));
  179. // We could add Aces support here as well if perf allows.
  180. color = TonemapFilmic(color);
  181. #endif
  182. OUT.m_specular = float4(color, 1.0);
  183. #ifdef SKYBOX_TWO_OUTPUTS
  184. OUT.m_reflection = float4(color, 1.0);
  185. #endif
  186. return OUT;
  187. }