float vc_shapeShadow(in vec3 pos) {
    const float size        = 0.01;
    const float lowEdge     = vc_altitude-vc_depth/2+8.0;
    const float highEdge    = vc_altitude+vc_depth/2-8.0;
    float tick              = animTick*0.04;
    vec3 windTick           = tick*vec3(1.0, -0.3, 0.0);

    float heightGradient    = smoothstep(pos.y, lowEdge, highEdge);

        pos.x          += exp2(heightGradient)*30.0;
        pos.xz          = rotateCoord(pos.xz, pi*0.1);

    vec3 pos2           = pos.xyz;
        pos2.xz         = rotateCoord(pos2.xz, -pi*0.1);

    float offset        = noise3D(pos.xyz, 4.2*size, -windTick.xyz*1.8)*2.5;

    vec3 posNoise       = pos+(offset-vec3(0.5, 0.0, 0.1))*(12.0+heightGradient*2.0);

    float noiseFade     = smoothstep(posNoise.y, lowEdge+15.0, vc_altitude+20.0);
    float invNoiseFade  = 1.0-noiseFade*0.5;

    float lowCoverage   = smoothstep(posNoise.y, lowEdge, lowEdge+vc_depth*0.11);
        lowCoverage     = 1.0-lowCoverage;
    float highCoverage  = smoothstep(pos.y, highEdge-vc_depth*0.66, highEdge);
        //highCoverage    = pow2(highCoverage);
    float lowFade       = linStep(posNoise.y, lowEdge, lowEdge+vc_depth*0.05);
        lowFade         = pow2(lowFade);
    float highFade      = smoothstep(posNoise.y, highEdge-vc_depth*0.15, highEdge);
        highFade        = 1.0-pow2(highFade);

    //float localCoverage = noise2D(pos.xz, 0.035*size, windTick.xz*0.5)*0.5;

    float shape     = worley2D(pos.xz, 2.2*size, windTick.xz)*2.0-1.0;
        shape      += perlin2D(pos2.xz, 5.4*size, windTick.xz*1.2)*0.75;
        shape      += worleyVolumeHQ(posNoise.xyz, 11.5*size, windTick.xyz*1.3)*0.7;

        #if s_vcDetail>=2
            shape      += worleyVolume(pos2.xyz, 21.2*size, windTick.xyz*1.3)*0.4;
        #endif

        #if s_vcDetail>=3
            shape      += noise3D(posNoise, 15.57*size, -windTick*2.2)*0.035*invNoiseFade;
        #endif

        shape      -= 0.5-(s_vcCoverage-1.0);

    #ifdef setBiomeEffects
        float biomeCoverage = 0.25*biomeCold+0.25*biomeHot+0.65*biomeDesert-0.15*biomeTropic+0.35*biomeSnow;
        shape      -= biomeCoverage;
    #endif
        shape      += wetness*0.5;

        shape      *= 1.7;

    //float fadeMod   = max(s_vcCoverage, 1.0);
        //fadeMod     = pow2(fadeMod)*0.5+fadeMod*0.5;

    float coverage  = 0.5;
        coverage   -= lowCoverage*0.5;
        coverage   -= highCoverage;
        coverage   *= highFade;
        coverage   *= lowFade;

        coverage    = max(coverage*1.5, 0.0);

    return coverage*6.0;
}

float getCloudShadow(in vec3 wpos, in vec3 wdir, const int samples) {
    const float lowEdge     = vc_altitude-vc_depth/2+8.0;
    const float highEdge    = vc_altitude+vc_depth/2-8.0;

    float invSteps  = vc_depth/samples;
    float stepSize  = invSteps / abs(wdir.y);

    vec3 increment  = wdir*stepSize;

    float fade      = smoothstep(abs(wdir.y), 0.125, 0.075);

    wpos += wpos.y <= vc_altitude ? wdir*(lowEdge-wpos.y) / wdir.y : vec3(0.0);

    float transmittance = 0.0;

    for (int i = 0; i<samples; wpos += increment) {
        transmittance += vc_shapeShadow(wpos);
    }

    return exp2(-transmittance*invLog2*stepSize)*(1.0-fade)+fade;
}