float getHorizonFade(in float GRAD, const float low, const float high) {
    float horizonFade = linStep(GRAD, low, high+0.05);
    return pow8(horizonFade*0.89);
}
float getLowDome(in float GRAD, const float height) {
    float lowDome   = sstep(GRAD, height-0.0, height+0.037);
    return (lowDome);
}
float getSunGlow(in float GRAD, const float low, const float high) {
    float sunGlow   = linStep(GRAD, low, high);
        sunGlow     = pow5(sunGlow*0.9);
        sunGlow    *= 0.8-timeNoon*0.5;
        sunGlow    *= (1.0-rainStrength*0.95);
    return sunGlow;
}
float getHorizonGlow(in float hGRAD, in float sGRAD, const float low, const float high) {
    float horizonGlow = saturateF(mix(pow3(sGRAD), pow2(sGRAD*1.1), timeNoon));
        horizonGlow = (linStep(hGRAD, low-horizonGlow*low, high-horizonGlow*0.05))*horizonGlow;
        horizonGlow = pow3(horizonGlow*1.2);
        horizonGlow = saturateF(horizonGlow*0.75);
        horizonGlow *= (1.0-rainStrength*0.85);
    return horizonGlow;
}
float getZenithDarken(in float GRAD, const float low, const float high) {
    float zenithFade = linStep(GRAD, low, high);
        zenithFade  = pow3(zenithFade*0.83)*1.58+0.92;
    return zenithFade;
}
vec3 getSunDisk(in float sunGrad, in float hBottom, in vec3 sunDiscCol) {
    float sunDisc   = linStep(sunGrad, 1.0-(setSunDiscRadius*0.017+0.001), 1.0-(setSunDiscRadius*0.017));
        sunDisc     = pow2(sunDisc);

    float sunLimb   = linStep(hBottom, 0.58, 0.70);
        sunLimb     = pow2(sunLimb);
    float sunLimbB  = linStep(sunGrad, 1.0-(setSunDiscRadius*0.02), 1.0-(setSunDiscRadius*0.011));
        sunLimbB    = pow2(sunLimbB)*0.7+0.3;
        sunLimb     = mix(sunLimb, 1.0, sunLimbB*timeSunrise+timeSunset);

    float sunLimb2   = 1.0-linStep(hBottom, 0.66, 0.71);
        sunLimb2     = pow2(sunLimb2);

    vec3 sunDiscColMod = mix(vec3(1.0), vec3(1.0, 0.0, 0.0), sunLimb)*sunLimb2*sunLimbB;

    return sunDisc*sunDiscCol*sunDiscColMod*10.0*(1.0-rainStrength)*(1.0+timeSunrise+timeSunset);
}

float getPlanetShadow(vec3 viewvec) {
    vec3 shadowvec = mix(normalize(vec.sun+viewvec), normalize(vec.up+viewvec), 0.85+sqrt(timeNoon)*0.15);
        //shadowvec  = normalize(shadowvec+viewvec);
    float grad     = 1.0-dot(shadowvec, viewvec);
        grad       = sstep(grad, 0.25, 0.35);
    return mix(grad, 1.0, sqrt(timeNoon)+timeNight);
}

vec3 getSky(in vec3 viewvec, const bool isRef) {
    vec3 nFrag      = -viewvec;
    vec3 hVec       = normalize(-vec.up+nFrag);
    vec3 hVec2      = normalize(vec.up+nFrag);
    vec3 sgVec      = normalize(vec.sun+nFrag);
    vec3 mgVec      = normalize(vec.moon+nFrag);

    float hlowMod   = -saturate(eyeAltitude*0.000002);
    float hhighMod  = saturate(eyeAltitude*0.000002);

    float hTop      = dot(hVec, nFrag)+hhighMod;
    float hBottom   = dot(hVec2, nFrag)+hlowMod;

    float zenith    = dot(hVec2, nFrag);
    float sun       = 1.0-dot(sgVec, nFrag);
    float moon      = 1.0-dot(mgVec, nFrag);
    float horizon   = 1.0-max(hBottom, hTop);

    const float horizonLevel = 0.688;

    float sunHorizon  = getHorizonGlow(horizon, sun, 0.0, 0.32);

    float horizonFade   = getHorizonFade(hBottom, 0.1, horizonLevel+0.02);    //gradient for brighter sky towards horizon
    float lowDome       = getLowDome(hBottom, horizonLevel);
    float zenithFade    = getZenithDarken(zenith, 0.0, horizonLevel+0.02);

    float horizonLight  = linStep(1.0-hTop, 0.21, 0.296);                    //gradient for horizon sunlight scatter
        horizonLight    = pow4(horizonLight)*0.65;

    float horizonGlow   = linStep(horizon, 0.16, 0.31);                    //gradient for additional horizon "glow"
        horizonGlow     = pow4(horizonGlow);

    float sunGlow       = mie(dot(viewvec, vec.sun), 0.89)*0.35;

    float sunHorizonGlow  = pow2(sunHorizon);

    float moonGlow      = pow(moon*0.85, 15.0);
        moonGlow        = saturate(moonGlow*1.05)*0.8;

    //float moonAlbedo    = sstep(moon, 0.85, 0.95)*timeNight;

    vec3 sunColor       = atmosSun;
    vec3 moonColor      = vec3(0.5, 0.78, 1.0)*0.15;

    //vec3 albedoCol      = sunDiscCol*5.0 + moonAlbedo*normalize(moonColor)*5.0;

        //albedoCol      *= 1.0-linStep(sun, 0.78, 0.86);

    float nightFix = (1.0-timeNight*0.9-timeMoon*0.1);

    vec3 sunScatterCol  = mix(colAtmosSunlight, colAtmosSunlight*colAtmosSunlight, timeSunrise*0.45+timeSunset*0.4)*2.0;
        sunScatterCol   = colorSat(sunScatterCol, 1.1);

    vec3 lowDomeColor   = colSky*0.7+(sunScatterCol*(0.07+horizonGlow*0.19)+colHorizon*0.12)*pow3(linStep(hTop, 0.0, 0.7))*nightFix*(1.0+timeNoon*0.8);
        lowDomeColor    += sunScatterCol*pow4(linStep(sun, 0.1, 1.0))*nightFix*timeSunHidden;
        lowDomeColor    += sunScatterCol*12.0*sunHorizon*nightFix*(1.0+timeNoon*0.6)*timeSunHidden;
        lowDomeColor    *= mix(vec3(1.0), vec3(0.3, 0.2, 1.0), 0.15);
        lowDomeColor    *= timeSunrise*0.35+timeNoon*0.75+timeSunset*0.35+timeNight*0.2;
        //lowDomeColor   *= mix(vec3(1.0), vec3(1.0, 0.5, 0.0)*2.4, sqrt(horizonLight)*0.4);

    vec3 horizonColor   = normalize(sunColor)*vec3avg(colHorizon)*2.2*(normalize(colHorizon)*0.8+0.2);
        horizonColor   *= mix(vec3(1.0), vec3(1.0, 0.62*(timeNoon*0.75+0.25), 0.2*timeNoon), 0.6*timeNoon)*0.5;

    float altitude  = max(1.0-saturate(eyeAltitude*0.00008), 0.05);

    vec3 sky        = colSky*(1.0-timeNight*0.4-timeMoon*0.49)*zenithFade*altitude;
        sky         = mix(sky, colHorizon, horizonFade*altitude);
        sky         = mix(sky, horizonColor, horizonLight*nightFix*altitude);
        sky         = mix(sky, sunScatterCol*10.0, saturate(sunHorizonGlow*0.3)*(1.0-timeNight));
        sky        += sunScatterCol*sunGlow*altitude*(nightFix*0.9+0.1);
        sky         = mix(sky, lowDomeColor, lowDome);

        sky   *= 6.3;

    #ifdef s_skyEarthShadow
        float planetShadow  = getPlanetShadow(nFrag);
        sky     = mix(colSky*0.3, sky, planetShadow*0.8+0.2);
    #endif

        //sky   += scene.albedo*albedoCol*2.0;

    if (isRef) {
        vec3 sunDiscCol     = (sunColor/2.2)*60.0*(1.0-timeMoon);
        sky   += getSunDisk(sun, hBottom, sunDiscCol);
    }

    return sky;
}

vec3 getSky(in vec3 viewvec) {
    return getSky(viewvec, false);
}