#define VOLUMETRIC_STEPS 4
#define MAX_VOLUMETRIC_STRENGTH 0.15  // Define a maximum strength for volumetric light

const float volumetricStepsInverse = 1.0 / VOLUMETRIC_STEPS;

vec3 getVolumetricLight(in vec3 feetPlayerPos, in float depth, in float dither){
    float feetPlayerDot = lengthSquared(feetPlayerPos);
    float feetPlayerDotInvSqrt = inversesqrt(feetPlayerDot);
    float feetPlayerDist = feetPlayerDot * feetPlayerDotInvSqrt;

    vec3 nFeetPlayerPos = feetPlayerPos * feetPlayerDotInvSqrt;

    float totalFogDensity = FOG_TOTAL_DENSITY;

    #ifdef FORCE_DISABLE_WEATHER
        if(isEyeInWater != 0) totalFogDensity *= TAU;
    #else
        totalFogDensity *= isEyeInWater == 0 ? (rainStrength * PI + 1.0) : TAU;
    #endif

    float heightFade = 1.0;

    // Fade VL, but do not apply to underwater VL
    if(isEyeInWater == 0 && nFeetPlayerPos.y > 0){
        heightFade = squared(squared(1.0 - squared(nFeetPlayerPos.y)));
        if(depth == 1) heightFade *= heightFade;

        #ifndef WORLD_CUSTOM_SKYLIGHT
            #ifndef FORCE_DISABLE_WEATHER
                heightFade += (1.0 - heightFade) * max(1.0 - eyeBrightFact, rainStrength * 0.5);
            #else
                heightFade += (1.0 - heightFade) * (1.0 - eyeBrightFact);
            #endif
        #endif
    }

    // Border fog
    #ifdef BORDER_FOG
        float volumetricFogDensity = 1.0 - exp2(-feetPlayerDist * totalFogDensity - exp2(feetPlayerDist / borderFar * 21.0 - 18.0));
    #else
        float volumetricFogDensity = 1.0 - exp2(-feetPlayerDist * totalFogDensity);
    #endif

    // Apply adjustments
    volumetricFogDensity *= heightFade * shdFade;

    #if defined VOLUMETRIC_LIGHTING && defined SHADOW_MAPPING
        vec3 endPos = vec3(shadowProjection[0].x, shadowProjection[1].y, shadowProjection[2].z) * (mat3(shadowModelView) * nFeetPlayerPos);
        endPos *= min(min(borderFar, shadowDistance), feetPlayerDist) * volumetricStepsInverse;

        vec3 startPos = vec3(shadowProjection[0].x, shadowProjection[1].y, shadowProjection[2].z) * shadowModelView[3].xyz + endPos * dither;
        startPos.z += shadowProjection[3].z;

        vec3 volumeData = vec3(0);

        for(int i = 0; i < VOLUMETRIC_STEPS; i++){
            volumeData += getShdCol(vec3(startPos.xy / (length(startPos.xy) * 2.0 + 0.2), startPos.z * 0.1) + 0.5);
            startPos += endPos;
        }

        // Clamp the volumetric light strength to prevent overstacking
        float volumetricStrength = min(MAX_VOLUMETRIC_STRENGTH, VOLUMETRIC_LIGHTING_STRENGTH + VOLUMETRIC_LIGHTING_STRENGTH * isEyeInWater);
        return volumeData * lightCol * (volumetricStrength * volumetricFogDensity * volumetricStepsInverse);
    #else
        if(isEyeInWater == 1) return lightCol * toLinear(fogColor) * (min(MAX_VOLUMETRIC_STRENGTH, VOLUMETRIC_LIGHTING_STRENGTH * 2.0) * volumetricFogDensity);
        #ifdef WORLD_CUSTOM_SKYLIGHT
            else return lightCol * (volumetricFogDensity * min(MAX_VOLUMETRIC_STRENGTH, VOLUMETRIC_LIGHTING_STRENGTH));
        #else
            else return lightCol * (volumetricFogDensity * eyeBrightFact * min(MAX_VOLUMETRIC_STRENGTH, VOLUMETRIC_LIGHTING_STRENGTH));
        #endif
    #endif
}