bool intersect_with_cloud_plane(vec3 WorldPos, inout vec3 StartPos, inout vec3 EndPos, vec3 RayDir) {
    if (WorldPos.y < CLOUD_LOWER_PLANE) {
        StartPos = intersectRayWithPlane(WorldPos, RayDir, CLOUD_LOWER_PLANE);
        EndPos = intersectRayWithPlane(WorldPos, RayDir, CLOUD_UPPER_PLANE);
        if (EndPos == vec3(0) || StartPos == vec3(0)) return false;
    }
    else if (WorldPos.y > CLOUD_UPPER_PLANE) {
        StartPos = intersectRayWithPlane(WorldPos, RayDir, CLOUD_UPPER_PLANE);
        EndPos = intersectRayWithPlane(WorldPos, RayDir, CLOUD_LOWER_PLANE);
        if (EndPos == vec3(0) || StartPos == vec3(0)) return false;
    }
    else {
        StartPos = vec3(0);
        if (RayDir.y > 0) {
            EndPos = intersectRayWithPlane(WorldPos, RayDir, CLOUD_UPPER_PLANE);
        }
        else {
            EndPos = intersectRayWithPlane(WorldPos, RayDir, CLOUD_LOWER_PLANE);
        }
    }
    return true;
}

void intersect_with_cloud_plane_light(vec3 WorldPos, inout vec3 EndPos, vec3 RayDir) {
    if (RayDir.y > 0) {
        EndPos = intersectRayWithPlane(WorldPos, RayDir, CLOUD_UPPER_PLANE);
    }
    else {
        EndPos = intersectRayWithPlane(WorldPos, RayDir, CLOUD_LOWER_PLANE);
    }
}

vec3 do_clouds(vec3 PlayerPos, vec3 PlayerPosN, vec3 Color, const int STEP_COUNT) {
    const float SIGMA = 0.2;
    const float DENSITY = 0.05;

    vec3 StartPos, EndPos;
    bool Hit = intersect_with_cloud_plane(cameraPosition, StartPos, EndPos, PlayerPosN);
    if (!Hit) return Color;

    vec3 Step = (EndPos - StartPos) / STEP_COUNT;
    float StepSize = length(Step);
    vec3 TotalTransmittance = vec3(1);
    vec3 FinalColor = vec3(0);
    vec2 Dither = blue_noise(gl_FragCoord.xy).rg;
    vec3 PlayerPosC = StartPos + Dither.x * Step;

    vec3 AmbientColor = dataBuf.AmbientColor; // This looks good

    float VdotL = dot(view_player(sLightPosN), PlayerPosN);
    float MiePhase = max(cs_phase(VdotL, 0.8), 1 / PI);
    for (int i = 1; i <= STEP_COUNT; i++) {
        vec3 WorldPosC = PlayerPosC + cameraPosition;

        float Density = noise_clouds(WorldPosC);
        if (Density <= 0.001) {
            PlayerPosC += Step;
            continue;
        }
        Density *= StepSize;
        Density *= DENSITY;

        vec3 Transmittance = vec3(exp(-Density * SIGMA));
        TotalTransmittance *= Transmittance;
        FinalColor += AmbientColor * Density * Transmittance * ISOTROPIC_PHASE;

        vec3 TransmittanceLight = vec3(1);
        vec3 EndPosL;
        intersect_with_cloud_plane_light(WorldPosC, EndPosL, view_player(sLightPosN));
        float StepSizeL = min(16, length(EndPosL) / 4);
        vec3 StepL = view_player(sLightPosN) * StepSizeL;
        vec3 WorldPosCL = WorldPosC + StepL * Dither.y;
        for (int i = 1; i <= 4; i++) {
            float DensityL = noise_clouds_base(WorldPosCL);
            DensityL *= StepSizeL;
            vec3 TransmittanceL = vec3(exp(-DensityL * SIGMA));
            TransmittanceLight *= TransmittanceL;
            WorldPosCL += StepL;
        }

        FinalColor += LightColorDirect * Density * TotalTransmittance * TransmittanceLight * MiePhase;

        PlayerPosC += Step;
    }

    vec3 CloudColor = Color * TotalTransmittance + FinalColor;

    float FogFactor = PlayerPosN.y * PlayerPosN.y;
    FogFactor = 1 - exp(-30 * FogFactor);
    CloudColor = mix(Color, CloudColor, FogFactor);

    return CloudColor;
}
