Files
FlaxEngine/Source/Shaders/ExponentialHeightFog.hlsl
2023-01-10 15:29:37 +01:00

91 lines
3.9 KiB
HLSL

// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#ifndef __EXPONENTIAL_HEIGHT_FOG__
#define __EXPONENTIAL_HEIGHT_FOG__
#include "./Flax/Common.hlsl"
#include "./Flax/Math.hlsl"
// Structure that contains information about exponential height fog
struct ExponentialHeightFogData
{
float3 FogInscatteringColor;
float FogMinOpacity;
float FogDensity;
float FogHeight;
float FogHeightFalloff;
float FogAtViewPosition;
float3 InscatteringLightDirection;
float ApplyDirectionalInscattering;
float3 DirectionalInscatteringColor;
float DirectionalInscatteringExponent;
float FogCutoffDistance;
float VolumetricFogMaxDistance;
float DirectionalInscatteringStartDistance;
float StartDistance;
};
float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance)
{
float3 cameraToPos = posWS - camWS;
float cameraToPosSqr = dot(cameraToPos, cameraToPos);
float cameraToPosLenInv = rsqrt(cameraToPosSqr);
float cameraToPosLen = cameraToPosSqr * cameraToPosLenInv;
float3 cameraToReceiverNorm = cameraToPos * cameraToPosLenInv;
float rayOriginTerms = exponentialHeightFog.FogAtViewPosition;
float rayLength = cameraToPosLen;
float rayDirectionY = cameraToPos.y;
// Apply start distance offset
skipDistance = max(skipDistance, exponentialHeightFog.StartDistance);
if (skipDistance > 0)
{
float excludeIntersectionTime = skipDistance * cameraToPosLenInv;
float cameraToExclusionIntersectionY = excludeIntersectionTime * cameraToPos.y;
float exclusionIntersectionY = camWS.y + cameraToExclusionIntersectionY;
rayLength = (1.0f - excludeIntersectionTime) * cameraToPosLen;
rayDirectionY = cameraToPos.y - cameraToExclusionIntersectionY;
float exponent = exponentialHeightFog.FogHeightFalloff * (exclusionIntersectionY - exponentialHeightFog.FogHeight);
rayOriginTerms = exponentialHeightFog.FogDensity * exp2(-exponent);
}
// Calculate the integral of the ray starting from the view to the object position with the fog density function
float falloff = max(-127.0f, exponentialHeightFog.FogHeightFalloff * rayDirectionY);
float lineIntegral = (1.0f - exp2(-falloff)) / falloff;
float lineIntegralTaylor = log(2.0f) - (0.5f * Pow2(log(2.0f))) * falloff;
float exponentialHeightLineIntegralCalc = rayOriginTerms * (abs(falloff) > 0.01f ? lineIntegral : lineIntegralTaylor);
float exponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * rayLength;
// Calculate the light that went through the fog
float expFogFactor = max(saturate(exp2(-exponentialHeightLineIntegral)), exponentialHeightFog.FogMinOpacity);
// Calculate the directional light inscattering
float3 inscatteringColor = exponentialHeightFog.FogInscatteringColor;
float3 directionalInscattering = 0;
BRANCH
if (exponentialHeightFog.ApplyDirectionalInscattering > 0)
{
float3 directionalLightInscattering = exponentialHeightFog.DirectionalInscatteringColor * pow(saturate(dot(cameraToReceiverNorm, exponentialHeightFog.InscatteringLightDirection)), exponentialHeightFog.DirectionalInscatteringExponent);
float dirExponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * max(rayLength - exponentialHeightFog.DirectionalInscatteringStartDistance, 0.0f);
float directionalInscatteringFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral));
directionalInscattering = directionalLightInscattering * (1.0f - directionalInscatteringFogFactor);
}
// Disable fog after a certain distance
FLATTEN
if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToPosLen > exponentialHeightFog.FogCutoffDistance)
{
expFogFactor = 1;
directionalInscattering = 0;
}
return float4(inscatteringColor * (1.0f - expFogFactor) + directionalInscattering, expFogFactor);
}
#endif