#ifndef EXPHEIGHTFOG_BASE #define EXPHEIGHTFOG_BASE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" #if defined(_SG_EXPFOG) float4 _SG_ExpFogParams; float4 _SG_ExpFogParams2; float4 _SG_ExpFogParams3; float4 _SG_ExpFogDirInscatteringCol; float4 _SG_ExpFogLightDir; float4 _SG_ExpFogColParams; #define CUSTOM_FOG_COORDS(ID) float4 _fogCoord : TEXCOORD##ID; #define CUSTOM_TRANSFER_FOG(v2f, vertex) v2f##._fogCoord = GetExponentialHeightFog(GetCameraPositionWS() - GetVertexPositionInputs(vertex.xyz).positionWS) #define CUSTOM_APPLY_FOG(v2f, pixelColor, lerpVal) pixelColor = lerp(pixelColor, pixelColor.rgb * v2f._fogCoord.a + v2f._fogCoord.rgb, saturate(lerpVal / _SG_ExpFogParams3.w)) // UE 4.22 HeightFogCommon.ush // Calculate the line integral of the ray from the camera to the receiver position through the fog density function // The exponential fog density function is d = GlobalDensity * exp(-HeightFalloff * y) inline float CalculateLineIntegralShared(float FogHeightFalloff, float RayDirectionY, float RayOriginTerms) { float Falloff = max(-127.0f, FogHeightFalloff * RayDirectionY); // if it's lower than -127.0, then exp2() goes crazy in OpenGL's GLSL. float LineIntegral = (1.0f - exp2(-Falloff)) / Falloff; return RayOriginTerms * LineIntegral; } // UE 4.22 HeightFogCommon.ush // @param WorldPositionRelativeToCamera = WorldPosition - InCameraPosition inline float4 GetExponentialHeightFog(float3 WorldPositionRelativeToCamera) // camera to vertex { float MinFogOpacity = _SG_ExpFogColParams.w; // Receiver float3 CameraToReceiver = -WorldPositionRelativeToCamera; float CameraToReceiverLengthSqr = dot(CameraToReceiver, CameraToReceiver); float CameraToReceiverLengthInv = rsqrt(CameraToReceiverLengthSqr); float CameraToReceiverLength = CameraToReceiverLengthSqr * CameraToReceiverLengthInv; float3 CameraToReceiverNormalized = CameraToReceiver * CameraToReceiverLengthInv; float RayOriginTerms = _SG_ExpFogParams.x; float RayLength = CameraToReceiverLength; float RayDirectionY = CameraToReceiver.y; // Factor in StartDistance float ExcludeDistance = _SG_ExpFogParams.w; float ExcludeIntersectionTime = ExcludeDistance * CameraToReceiverLengthInv; float CameraToExclusionIntersectionY = ExcludeIntersectionTime * CameraToReceiver.y; float ExclusionIntersectionY = GetCameraPositionWS().y + CameraToExclusionIntersectionY; float ExclusionIntersectionToReceiverY = CameraToReceiver.y - CameraToExclusionIntersectionY; float Exponent = max(-127.0f, _SG_ExpFogParams.y * (ExclusionIntersectionY - (GetCameraPositionWS().y + _SG_ExpFogParams3.y))); RayLength = (1.0f - ExcludeIntersectionTime) * CameraToReceiverLength; RayDirectionY = ExclusionIntersectionToReceiverY; RayOriginTerms = _SG_ExpFogParams3.x * exp2(-Exponent); float ExponentialHeightLineIntegralShared = CalculateLineIntegralShared(_SG_ExpFogParams.y, RayDirectionY, RayOriginTerms); float ExponentialHeightLineIntegral = ExponentialHeightLineIntegralShared * RayLength; float3 InscatteringColor = _SG_ExpFogColParams.xyz; float3 DirectionalInscattering = 0; float DirectionalInscatteringStartDistance = _SG_ExpFogLightDir.w; // Setup a cosine lobe around the light direction to approximate inscattering from the directional light off of the ambient haze; float3 DirectionalLightInscattering = _SG_ExpFogDirInscatteringCol.xyz * pow(saturate(dot(CameraToReceiverNormalized, _SG_ExpFogLightDir.xyz)), _SG_ExpFogDirInscatteringCol.w); // Calculate the line integral of the eye ray through the haze, using a special starting distance to limit the inscattering to the distance float DirExponentialHeightLineIntegral = ExponentialHeightLineIntegralShared * max(RayLength - DirectionalInscatteringStartDistance, 0.0f); // Calculate the amount of light that made it through the fog using the transmission equation float DirectionalInscatteringFogFactor = saturate(exp2(-DirExponentialHeightLineIntegral)); // Final inscattering from the light DirectionalInscattering = DirectionalLightInscattering * (1 - DirectionalInscatteringFogFactor); // Calculate the amount of light that made it through the fog using the transmission equation float ExpFogFactor = max(saturate(exp2(-ExponentialHeightLineIntegral)), MinFogOpacity); float3 FogColor = (InscatteringColor) * (1 - ExpFogFactor) + DirectionalInscattering; return float4(FogColor, ExpFogFactor); } inline float3 ApplyFogUnrealExp2Fog(float3 finalColor, float3 worldPos) { float4 fogCoord = GetExponentialHeightFog(worldPos.xyz - GetCameraPositionWS().xyz); float lerpVal = distance(GetCameraPositionWS().xyz, worldPos.xyz); return lerp(finalColor, finalColor * fogCoord.a + fogCoord.rgb, saturate(lerpVal / _SG_ExpFogParams3.w)); } inline float3 ApplyFogUnrealExp2FogWithOffset(float3 finalColor, float3 worldPos, float fogFactor) { float4 fogCoord = GetExponentialHeightFog(worldPos.xyz - GetCameraPositionWS().xyz); float lerpVal = distance(GetCameraPositionWS().xyz, worldPos.xyz); return lerp(finalColor, finalColor * fogCoord.a + fogCoord.rgb, saturate(lerpVal / _SG_ExpFogParams3.w) * fogFactor); } #endif #endif