#if !defined CLOUD_SHADOW_LIB
#define CLOUD_SHADOW_LIB
    float calculateCloudShadow(in vec3 startPosition, in vec3 direction, in float steps) {
        #ifdef VOLUMETRIC_CLOUDS
            float samples = steps;

            vec2 distances = vec2(cloudsAltitude, cloudsMaxAltitude);
            distances = (distances - startPosition.y) / direction.y;
            if (distances.y < distances.x) distances = distances.yx;
            distances.x = max(distances.x, 0.0);
            if (distances.y < distances.x) return 1.0;

            float stepsize = (distances.y - distances.x) / samples;

            vec3 increment = direction * stepsize;
            vec3 position = startPosition + direction * distances.x;

            position += increment;

            float transmittance = 1.0;
            float opticalDepth = 0.0;

            for(int i = 0; i < samples; ++i, position += increment) {
                float density = calculateCloudShape(position);
                if(density <= 0.0) { continue; }
                float stepOpticalDepth = cloudsExtinctionCoefficient * stepsize * density;
                float stepTransmittance = exp(-stepOpticalDepth);
                if(transmittance <= 1e-5) break;

                opticalDepth += stepOpticalDepth;
                transmittance *= stepTransmittance;
            }

            return transmittance;
        #else
            return 1.0;
        #endif
    }
#endif