Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
391afb3
add exponential height fog
jiayev Oct 24, 2025
544918b
directional light inscattering
jiayev Oct 25, 2025
5f06d6e
more scattering stuff
jiayev Oct 26, 2025
0d57ea8
dynamic cubemaps for inscattering
jiayev Oct 26, 2025
87a3334
Merge branch 'dev' into height-fog
jiayev Jan 12, 2026
72efc16
adapt to weather
jiayev Jan 12, 2026
83c187c
Merge branch 'dev' into height-fog
jiayev Jan 12, 2026
9fd8f06
Merge branch 'dev' into height-fog
jiayev Jan 13, 2026
5fe4a69
Merge branch 'dev' into height-fog
jiayev Jan 13, 2026
69eb503
adapt to weather
jiayev Jan 13, 2026
4b40c6f
add sunlight fadeout in fog
jiayev Jan 13, 2026
8073566
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Jan 13, 2026
3102cb5
Merge branch 'dev' into height-fog
jiayev Jan 14, 2026
6777eb1
try fix water, idk
jiayev Jan 14, 2026
be7632a
fix compile error
jiayev Jan 14, 2026
798496c
fix some blending
jiayev Jan 17, 2026
d1ee6af
add alpha back
jiayev Jan 17, 2026
68d74a1
Merge branch 'dev' into height-fog
jiayev Jan 26, 2026
e27754d
Merge branch 'dev' into height-fog
jiayev Jan 28, 2026
7b72d4d
Merge branch 'dev' into height-fog
jiayev Feb 1, 2026
d56ee70
fix(water): remove unnecessary else statement in fog calculation
jiayev Feb 1, 2026
5a6b74a
fix fog blending with new water
jiayev Feb 4, 2026
e535d17
Merge branch 'dev' into height-fog
jiayev Feb 4, 2026
d0832db
Merge branch 'dev' into height-fog
jiayev Feb 7, 2026
1e858fb
Merge branch 'dev' into height-fog
jiayev Feb 9, 2026
7a91928
Merge branch 'dev' into height-fog
jiayev Feb 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#ifndef DYNAMICCUBEMAPS_HLSLI
#define DYNAMICCUBEMAPS_HLSLI

#include "Common/BRDF.hlsli"

#if defined(SKYLIGHTING)
Expand Down Expand Up @@ -264,3 +267,4 @@ namespace DynamicCubemaps
}
#endif // !WATER
}
#endif // DYNAMICCUBEMAPS_HLSLI
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#ifndef __EXPONENTIAL_HEIGHT_FOG_HLSLI__
#define __EXPONENTIAL_HEIGHT_FOG_HLSLI__

#include "Common/SharedData.hlsli"

# if defined(DYNAMIC_CUBEMAPS)
# include "DynamicCubemaps/DynamicCubemaps.hlsli"
# endif

namespace ExponentialHeightFog
{
float4 GetExponentialHeightFog(float3 positionWS, float3 cameraWS, float3 fogColor)
{
float fogHeightFalloff = SharedData::exponentialHeightFogSettings.fogHeightFalloff * 0.001f;
float fogDensity = SharedData::exponentialHeightFogSettings.fogDensity * 0.001f;
if (fogDensity <= 0.0f)
{
return 0.0f;
}
float3 viewToPos = positionWS;
float viewToPosLength = length(viewToPos);
float viewToPosLengthInv = rcp(viewToPosLength);

float rayOriginTerms = fogDensity * exp2(-fogHeightFalloff * max(cameraWS.z - SharedData::exponentialHeightFogSettings.fogHeight, 0));
float rayLength = viewToPosLength;
float rayDirectionZ = viewToPos.z;

if (SharedData::exponentialHeightFogSettings.startDistance > 0)
{
float excludeIntersectionTime = SharedData::exponentialHeightFogSettings.startDistance * viewToPosLengthInv;
float cameraToExclusionIntersectionZ = excludeIntersectionTime * viewToPos.z;
float exclusionIntersectionZ = cameraWS.z + cameraToExclusionIntersectionZ;
rayLength = (1.0f - excludeIntersectionTime) * viewToPosLength;
rayDirectionZ = viewToPos.z - cameraToExclusionIntersectionZ;
float exponent = fogHeightFalloff * max(exclusionIntersectionZ - SharedData::exponentialHeightFogSettings.fogHeight, 0);
rayOriginTerms = fogDensity * exp2(-exponent);
}

float falloff = fogHeightFalloff * rayDirectionZ;
float lineIntegral = (1.0f - exp2(-falloff)) / falloff;
float lineIntegralTaylor = 0.69314718056f - 0.24022650695f * falloff; // log(2) - (0.5 * (log(2)^2)) * falloff
float exponentialHeightLineIntegralCalc = rayOriginTerms * (abs(falloff) > 0.01f ? lineIntegral : lineIntegralTaylor);
float exponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * rayLength;

float expFogFactor = saturate(exp2(-exponentialHeightLineIntegral));

# if defined(DYNAMIC_CUBEMAPS)
if (SharedData::exponentialHeightFogSettings.useDynamicCubemaps > 0)
{
float3 tintColor = lerp(fogColor, SharedData::exponentialHeightFogSettings.inscatteringTint.xyz, SharedData::exponentialHeightFogSettings.inscatteringTint.w);
float3 cubemapColor = DynamicCubemaps::EnvReflectionsTexture.SampleLevel(SampColorSampler, normalize(lerp(positionWS, float3(0,0,1), saturate((SharedData::exponentialHeightFogSettings.cubemapMipLevel + 1) / 8))), SharedData::exponentialHeightFogSettings.cubemapMipLevel).xyz;
fogColor = tintColor * cubemapColor * (1.0f - expFogFactor);
}
# endif
Comment thread
jiayev marked this conversation as resolved.

float3 directionalInscattering = 0;

// Calculate directional light inscattering
if (SharedData::exponentialHeightFogSettings.directionalInscatteringMultiplier > 0)
{
float3 directionalLightInscattering = SharedData::DirLightColor.xyz * pow(saturate(dot(normalize(positionWS), SharedData::DirLightDirection.xyz)), SharedData::exponentialHeightFogSettings.directionalInscatteringExponent) / (2 * Math::TAU);
float dirExponentialHeightLineIntegral = exponentialHeightLineIntegralCalc * max(rayLength - SharedData::exponentialHeightFogSettings.startDistance, 0);
float dirExpFogFactor = saturate(exp2(-dirExponentialHeightLineIntegral));
directionalInscattering = directionalLightInscattering * (1 - dirExpFogFactor) * SharedData::exponentialHeightFogSettings.directionalInscatteringMultiplier;
}

fogColor += directionalInscattering;
return float4(fogColor, 1.0f - expFogFactor);
}

float GetSunlightFogAttenuation(float3 positionWS, float3 cameraWS)
{
float fogHeightFalloff = SharedData::exponentialHeightFogSettings.fogHeightFalloff * 0.001f;
float fogDensity = SharedData::exponentialHeightFogSettings.fogDensity * 0.001f;
if (fogDensity <= 0.0f)
{
return 1.0f;
}

float exponent = fogHeightFalloff * max(positionWS.z + cameraWS.z - SharedData::exponentialHeightFogSettings.fogHeight, 0.0f);
float localDensity = fogDensity * exp2(-exponent);

float3 lightDir = SharedData::DirLightDirection.xyz;
float lightDirZ = lightDir.z;

float exponentialHeightLineIntegral = 0.0f;

// Integral = Density * (1 - exp2(-slope * inf)) / slope
if (lightDirZ > 0.001f)
{
float slope = max(fogHeightFalloff * lightDirZ, 1e-8f);
exponentialHeightLineIntegral = localDensity / slope;
}
else
{
return 0.0f;
}

return saturate(exp2(-exponentialHeightLineIntegral));
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[Info]
Version = 1-0-0
16 changes: 16 additions & 0 deletions package/Shaders/Common/SharedData.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,21 @@ namespace SharedData
uint3 _padding;
};

struct ExponentialHeightFogSettings
{
uint enabled;
uint useDynamicCubemaps;
float startDistance;
float fogHeight;
float fogHeightFalloff;
float fogDensity;
float directionalInscatteringMultiplier;
float directionalInscatteringExponent;
float4 inscatteringTint;
float cubemapMipLevel;
float3 pad;
};

cbuffer FeatureData : register(b6)
{
GrassLightingSettings grassLightingSettings;
Expand All @@ -255,6 +270,7 @@ namespace SharedData
ExtendedTranslucencySettings extendedTranslucencySettings;
LinearLightingSettings linearLightingSettings;
TerrainBlendingSettings terrainBlendingSettings;
ExponentialHeightFogSettings exponentialHeightFogSettings;
};

Texture2D<float4> DepthTexture : register(t17);
Expand Down
17 changes: 17 additions & 0 deletions package/Shaders/DistantTree.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ const static float DepthOffsets[16] = {
# include "IBL/IBL.hlsli"
# endif

# if defined(EXP_HEIGHT_FOG)
# define SampColorSampler SampDiffuse
# include "ExponentialHeightFog/ExponentialHeightFog.hlsli"
# endif

# define LinearSampler SampDiffuse

# include "Common/ShadowSampling.hlsli"
Expand Down Expand Up @@ -237,6 +242,12 @@ PS_OUTPUT main(PS_INPUT input)
float llDirLightMult = (SharedData::linearLightingSettings.enableLinearLighting && !SharedData::linearLightingSettings.isDirLightLinear) ? SharedData::linearLightingSettings.dirLightMult : 1.0f;
float3 diffuseColor = Color::DirectionalLight(SharedData::DirLightColor.xyz / max(llDirLightMult, 1e-5), SharedData::linearLightingSettings.isDirLightLinear) * dirShadow * 0.5 * llDirLightMult * Color::VanillaNormalization();

# if defined(EXP_HEIGHT_FOG)
if (SharedData::exponentialHeightFogSettings.enabled) {
diffuseColor *= ExponentialHeightFog::GetSunlightFogAttenuation(input.WorldPosition.xyz, FrameBuffer::CameraPosAdjust[eyeIndex].xyz);
}
# endif

float3 ddx = ddx_coarse(input.WorldPosition.xyz);
float3 ddy = ddy_coarse(input.WorldPosition.xyz);
float3 normal = -normalize(cross(ddx, ddy));
Expand Down Expand Up @@ -272,6 +283,12 @@ PS_OUTPUT main(PS_INPUT input)
float llDirLightMult = (SharedData::linearLightingSettings.enableLinearLighting && !SharedData::linearLightingSettings.isDirLightLinear) ? SharedData::linearLightingSettings.dirLightMult : 1.0f;
float3 diffuseColor = Color::DirectionalLight(SharedData::DirLightColor.xyz / max(llDirLightMult, 1e-5), SharedData::linearLightingSettings.isDirLightLinear) * dirShadow * 0.5 * llDirLightMult * Color::VanillaNormalization();

# if defined(EXP_HEIGHT_FOG)
if (SharedData::exponentialHeightFogSettings.enabled) {
diffuseColor *= ExponentialHeightFog::GetSunlightFogAttenuation(input.WorldPosition.xyz, FrameBuffer::CameraPosAdjust[eyeIndex].xyz);
}
# endif

float3 ddx = ddx_coarse(input.WorldPosition.xyz);
float3 ddy = ddy_coarse(input.WorldPosition.xyz);
float3 normal = normalize(cross(ddx, ddy));
Expand Down
43 changes: 35 additions & 8 deletions package/Shaders/Effect.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,11 @@ cbuffer PerGeometry : register(b2)
# include "IBL/IBL.hlsli"
# endif

# if defined(EXP_HEIGHT_FOG)
# define SampColorSampler SampBaseSampler
# include "ExponentialHeightFog/ExponentialHeightFog.hlsli"
# endif

# include "Common/ShadowSampling.hlsli"

float ComputeShadowVariance(float shadow)
Expand All @@ -552,6 +557,13 @@ float3 GetLightingColor(float3 msPosition, float3 worldPosition, float4 screenPo
if ((Permutation::ExtraShaderDescriptor & Permutation::ExtraFlags::EffectShadows)) {
float llDirLightMult = (SharedData::linearLightingSettings.enableLinearLighting && !SharedData::linearLightingSettings.isDirLightLinear) ? SharedData::linearLightingSettings.dirLightMult : 1.0f;
float3 dirLightColor = Color::DirectionalLight(SharedData::DirLightColor.xyz / max(llDirLightMult, 1e-5), SharedData::linearLightingSettings.isDirLightLinear) * llDirLightMult * 0.5 * Color::EffectLightingMult();

# if defined(EXP_HEIGHT_FOG)
if (SharedData::exponentialHeightFogSettings.enabled) {
dirLightColor *= ExponentialHeightFog::GetSunlightFogAttenuation(worldPosition.xyz, FrameBuffer::CameraPosAdjust[eyeIndex].xyz);
}
# endif

float3 ambientColor = max(0, mul(SharedData::DirectionalAmbient, float4(0, 0, 1, 1)));

# if defined(IBL)
Expand Down Expand Up @@ -825,27 +837,42 @@ PS_OUTPUT main(PS_INPUT input)
}
# endif

lightColor = Color::EffectMult(lightColor);

# if !defined(MOTIONVECTORS_NORMALS)
# if defined(ADDBLEND)
float3 blendedColor = lightColor * (1 - Color::FogAlpha(input.FogParam.w).xxx);
# elif defined(MULTBLEND) || defined(MULTBLEND_DECAL)
float3 blendedColor = lerp(lightColor, 1.0.xxx, saturate(1.5 * Color::FogAlpha(input.FogParam.w)).xxx);
# else
float fogFactor = Color::FogAlpha(input.FogParam.w);
float3 fogColor = Color::Fog(input.FogParam.xyz);
# if defined(IBL)
# if defined(IBL)
if (SharedData::iblSettings.EnableDiffuseIBL && !SharedData::InInterior) {
fogColor = ImageBasedLighting::GetFogIBLColor(fogColor);
}
# endif
# if defined(EXP_HEIGHT_FOG)
if (SharedData::exponentialHeightFogSettings.enabled) {
float4 exponentialHeightFog = ExponentialHeightFog::GetExponentialHeightFog(input.WorldPosition.xyz, FrameBuffer::CameraPosAdjust[eyeIndex].xyz, fogColor);
# if defined(ADDBLEND) || defined(MULTBLEND) || defined(MULTBLEND_DECAL)
fogColor = exponentialHeightFog.xyz;
fogFactor = exponentialHeightFog.w;
# else
fogColor = lightColor;
alpha *= 1 - exponentialHeightFog.w;
# endif
float3 blendedColor = lerp(lightColor, fogColor, Color::FogAlpha(input.FogParam.w).xxx);
}
# endif
# if defined(ADDBLEND)
float3 blendedColor = lightColor * (1 - fogFactor);
# elif defined(MULTBLEND) || defined(MULTBLEND_DECAL)
float3 blendedColor = lerp(lightColor, 1.0.xxx, saturate(1.5 * fogFactor).xxx);
# else
float3 blendedColor = lerp(lightColor, fogColor, fogFactor.xxx);
# endif
# else
float3 blendedColor = lightColor.xyz;
# endif

alpha = Color::EffectAlpha(alpha);

float4 finalColor = float4(Color::EffectMult(blendedColor), alpha);
float4 finalColor = float4(blendedColor, alpha);
# if defined(MULTBLEND_DECAL)
finalColor.xyz *= alpha;
# else
Expand Down
20 changes: 20 additions & 0 deletions package/Shaders/ISSAOComposite.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ float SimplexNoise(float3 v)
# include "IBL/IBL.hlsli"
# endif

# if defined(EXP_HEIGHT_FOG) && defined(APPLY_FOG)
SamplerState SampColorSampler : register(s9);
# include "ExponentialHeightFog/ExponentialHeightFog.hlsli"
# endif

PS_OUTPUT main(PS_INPUT input)
{
PS_OUTPUT psout;
Expand Down Expand Up @@ -180,9 +185,24 @@ PS_OUTPUT main(PS_INPUT input)
fogColor = ImageBasedLighting::GetFogIBLColor(fogColor);
}
# endif
# if defined(EXP_HEIGHT_FOG)
uint eyeIndex = Stereo::GetEyeIndexFromTexCoord(input.TexCoord.xy);
float4 positionWS = float4(2 * float2(input.TexCoord.x, -input.TexCoord.y + 1) - 1, depth, 1);
positionWS = mul(FrameBuffer::CameraViewProjInverse[eyeIndex], positionWS);
positionWS.xyz = positionWS.xyz / positionWS.w;
if (SharedData::exponentialHeightFogSettings.enabled) {
float4 exponentialHeightFog = ExponentialHeightFog::GetExponentialHeightFog(positionWS.xyz, FrameBuffer::CameraPosAdjust[eyeIndex].xyz, fogColor);
fogColor = exponentialHeightFog.xyz;
fogFactor = exponentialHeightFog.w;
}
if (depth < 0.999999 || SharedData::exponentialHeightFogSettings.enabled) {
composedColor.xyz = (SharedData::exponentialHeightFogSettings.enabled ? 1.0 : FogNearColor.w) * lerp(composedColor.xyz, fogColor, fogFactor);
}
# else
if (depth < 0.999999) {
composedColor.xyz = FogNearColor.w * lerp(composedColor.xyz, fogColor, Color::FogAlpha(fogFactor));
}
# endif
# endif

# if !defined(VR)
Expand Down
21 changes: 20 additions & 1 deletion package/Shaders/Lighting.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,10 @@ float GetSnowParameterY(float texProjTmp, float alpha)
# include "IBL/IBL.hlsli"
# endif

# if defined(EXP_HEIGHT_FOG)
# include "ExponentialHeightFog/ExponentialHeightFog.hlsli"
# endif

# include "Common/LightingEval.hlsli"

PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
Expand Down Expand Up @@ -2392,6 +2396,13 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
float3 dirLightColor = Color::DirectionalLight(DirLightColor.xyz / max(llDirLightMult, 1e-5), SharedData::linearLightingSettings.isDirLightLinear) * llDirLightMult;
float3 dirLightColorMultiplier = 1;


# if defined(EXP_HEIGHT_FOG)
if (SharedData::exponentialHeightFogSettings.enabled) {
dirLightColor *= ExponentialHeightFog::GetSunlightFogAttenuation(input.WorldPosition.xyz, FrameBuffer::CameraPosAdjust[eyeIndex].xyz);
}
# endif

# if defined(WATER_EFFECTS)
dirLightColorMultiplier *= WaterEffects::ComputeCaustics(waterData, input.WorldPosition.xyz, eyeIndex);
# endif
Expand Down Expand Up @@ -3014,13 +3025,21 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
# if !defined(DEFERRED)
color.xyz = Color::IrradianceToGamma(Color::IrradianceToLinear(color.xyz) + specularColor);
float3 fogColor = Color::Fog(input.FogParam.xyz);
float fogFactor = Color::FogAlpha(input.FogParam.w);
# if defined(IBL)
if (SharedData::iblSettings.EnableDiffuseIBL && !SharedData::InInterior) {
fogColor = ImageBasedLighting::GetFogIBLColor(fogColor);
}
# endif
# if defined(EXP_HEIGHT_FOG)
if (SharedData::exponentialHeightFogSettings.enabled) {
float4 exponentialHeightFog = ExponentialHeightFog::GetExponentialHeightFog(input.WorldPosition.xyz, FrameBuffer::CameraPosAdjust[eyeIndex].xyz, fogColor);
fogColor = exponentialHeightFog.xyz;
fogFactor = exponentialHeightFog.w;
}
# endif
if (FrameBuffer::FrameParams.y && FrameBuffer::FrameParams.z)
color.xyz = lerp(color.xyz, fogColor, Color::FogAlpha(input.FogParam.w));
color.xyz = lerp(color.xyz, fogColor, fogFactor);
# endif

# if defined(TESTCUBEMAP) && defined(ENVMAP) && defined(DYNAMIC_CUBEMAPS)
Expand Down
10 changes: 10 additions & 0 deletions package/Shaders/RunGrass.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,10 @@ cbuffer AlphaTestRefCB : register(b11)
# include "IBL/IBL.hlsli"
# endif

# if defined(EXP_HEIGHT_FOG)
# include "ExponentialHeightFog/ExponentialHeightFog.hlsli"
# endif

# define LinearSampler SampBaseSampler

# include "Common/ShadowSampling.hlsli"
Expand Down Expand Up @@ -586,6 +590,12 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace : SV_IsFrontFace)
float3 dirLightColor = Color::DirectionalLight(SharedData::DirLightColor.xyz / max(llDirLightMult, 1e-5), SharedData::linearLightingSettings.isDirLightLinear) * llDirLightMult;
float3 dirLightColorMultiplier = 1;

# if defined(EXP_HEIGHT_FOG)
if (SharedData::exponentialHeightFogSettings.enabled) {
dirLightColor *= ExponentialHeightFog::GetSunlightFogAttenuation(input.WorldPosition.xyz, FrameBuffer::CameraPosAdjust[eyeIndex].xyz);
}
# endif

float dirLightAngle = dot(normal, SharedData::DirLightDirection.xyz);

float4 shadowColor = TexShadowMaskSampler.Load(int3(input.HPosition.xy, 0));
Expand Down
Loading