	#if FLUFFY_CLOUD==1
float CloudNoise(vec2 coord,vec2 wind){
float noise=texture2D(noisetex,coord*1+wind*.55).x;
noise+=texture2D(noisetex,coord*.5+wind*.45).x*-2.;
noise+=texture2D(noisetex,coord*.25+wind*.35).x*2.;
noise+=texture2D(noisetex,coord*.125+wind*.25).x*5.;
noise+=texture2D(noisetex,coord*.0625+wind*.15).x*9.;
noise+=texture2D(noisetex,coord*.03125+wind*.05).x*10.;
noise+=texture2D(noisetex,coord*.015625+wind*.05).x*-12.;
return noise;
}
#endif

	#if FLUFFY_CLOUD==2
float CloudNoise(vec2 coord,vec2 wind){
float noise=texture2D(noisetex,coord*1+wind*.55).x;
noise+=texture2D(noisetex,coord*.5+wind*.45).x*-2.;
noise+=texture2D(noisetex,coord*.25+wind*.35).x*2.;
noise+=texture2D(noisetex,coord*.125+wind*.25).x*-5.;
noise+=texture2D(noisetex,coord*.0625+wind*.15).x*15.;
noise+=texture2D(noisetex,coord*.03125+wind*.05).x*15.;
noise+=texture2D(noisetex,coord*.015625+wind*.05).x*-12.;
return noise;
}
#endif

	#if FLUFFY_CLOUD==3
float CloudNoise(vec2 coord,vec2 wind){
float noise=texture2D(noisetex,coord*1+wind*.55).x;
noise+=texture2D(noisetex,coord*.5+wind*.45).x*-3.;
noise+=texture2D(noisetex,coord*.25+wind*.34).x*3.;
noise+=texture2D(noisetex,coord*.125+wind*.25).x*-5.;
noise+=texture2D(noisetex,coord*.0625+wind*.15).x*20.;
noise+=texture2D(noisetex,coord*.03125+wind*.10).x*20.;
noise+=texture2D(noisetex,coord*.012500+wind*.5).x*4.;
noise+=texture2D(noisetex,coord*.025000+wind*.5).x*-25.;
return noise;
}
#endif

float CloudCoverage(float noise,float cosT,float coverage){
	float noiseMix=mix(noise,31.,.43*rainStrength);
	float noiseFade=clamp(sqrt(cosT*10.),0.,1.);
	float noiseCoverage=((coverage*coverage)+CLOUD_AMOUNT);
	float multiplier=1.-.5*rainStrength;
	
	return max(noiseMix*noiseFade-noiseCoverage,0.)*multiplier;
}

vec4 DrawCloud(vec3 viewPos,float dither,vec3 lightCol,vec3 ambientCol){
	float cosT=dot(normalize(viewPos),upVec);
	float cosS=dot(normalize(viewPos),sunVec);
	
	#if AA>1
	dither=fract(16.*frameTimeCounter+dither);
	#endif
	
	float cloud=0.;
	float cloudGradient=0.;
	float gradientMix=dither*.1667;
	float colorMultiplier=CLOUD_BRIGHTNESS*(.5-.25*(1.-sunVisibility)*(1.-rainStrength));
	float noiseMultiplier=CLOUD_THICKNESS*.25;
	float scattering=pow(cosS*.5*(2.*sunVisibility-1.)+.5,6.);
	
	vec2 wind=vec2(frametime*CLOUD_SPEED*.0005,
		sin(frametime*CLOUD_SPEED*.05)*.002)*CLOUD_HEIGHT/20.;
		
	vec3 cloudcolor=vec3(0.);
		
	if(cosT>.025){
		vec3 wpos=normalize((gbufferModelViewInverse*vec4(viewPos,1.)).xyz);
		for(int i=0;i<CLOUD_QUALITY;i++){
			if(cloud>.99)break;
			vec3 planeCoord=wpos*(((CLOUD_HEIGHT/1.5)+(i+dither))/wpos.y)*.004;
			vec2 coord=cameraPosition.xz*.00025+planeCoord.xz;
			float coverage=float(i-3.+dither)*.667;
			
			float noise=CloudNoise(coord,wind);
			noise=CloudCoverage(noise,cosT,coverage)*noiseMultiplier;
			noise=noise/pow(pow(noise,2.5)+1.,.4);
			
			cloudGradient=mix(cloudGradient,
				mix(gradientMix*gradientMix,1.-noise,.25),
				noise*(1.-cloud*cloud));
				cloud=mix(cloud,1.,noise);
				gradientMix+=.2;
			}
			cloudcolor=mix(ambientCol*(.5*sunVisibility+.5),
			lightCol*(1.+scattering),
			cloudGradient*cloud);
		
		cloudcolor.r*=(1.0 + sunVisibility*(0.25-timeBrightness*0.25)*(1-.4*rainStrength));
		cloudcolor+=lightNight*lightNight*lightNight*lightNight*2;
		cloud*=sqrt(sqrt(clamp(cosT*10.-1.,0.,1.)))*(1.-.6*rainStrength);
		
	}
	
	return vec4(cloudcolor*colorMultiplier,pow(cloud,2)*CLOUD_OPACITY);
}

float CloudNoiseEnd(vec2 coord, vec2 wind){
	float noise = texture2D(noisetex, coord*1        + wind * 0.55).x;
		  noise+= texture2D(noisetex, coord*0.5      + wind * 0.45).x * -2.0;
		  noise+= texture2D(noisetex, coord*0.25     + wind * 0.35).x * 2.0;
		  noise+= texture2D(noisetex, coord*0.125    + wind * 0.25).x * -5.0;
		  noise+= texture2D(noisetex, coord*0.0625   + wind * 0.15).x * 20.0;
		  noise+= texture2D(noisetex, coord*0.03125  + wind * 0.05).x * 20.0;
		  noise+= texture2D(noisetex, coord*0.015625 + wind * 0.05).x * -15.0;
	return noise;
}

float CloudCoverageEnd(float noise,float cosT,float coverage){
	float noiseMix=mix(noise,21.,.33*rainStrength);
	float noiseFade=clamp(sqrt(cosT*10.),0.,1.);
	float noiseCoverage=((coverage*coverage)+ CLOUD_AMOUNT_END);
	float multiplier=1.-.5*rainStrength;
	
	return max(noiseMix*noiseFade-noiseCoverage,0.)*multiplier;
}

vec4 DrawEndCloud(vec3 viewPos,float dither,vec3 lightCol){
	float cosT=dot(normalize(viewPos),upVec);
	float cosS=dot(normalize(viewPos),sunVec);
	
	#if AA>1
	dither=fract(16.*frameTimeCounter+dither);
	#endif
	
	float cloud=0.;
	float cloudGradient=0.;
	float gradientMix=dither*.5;
	float colorMultiplier=CLOUD_BRIGHTNESS_END*(.5-.25*(1.-sunVisibility)*(1.-rainStrength));
	float noiseMultiplier=CLOUD_THICKNESS_END*.15;
	float scattering=pow(cosS*.5+.5,6.);
	
	vec2 wind=vec2(frametime*CLOUD_SPEED_END*.005,
		sin(frametime*CLOUD_SPEED_END*.05)*.002)*CLOUD_HEIGHT_END/25.;
		
		vec3 cloudcolor=vec3(0.);
		
	if(cosT>.1){
		vec3 wpos=normalize((gbufferModelViewInverse*vec4(viewPos,1.)).xyz);
		for(int i=0;i<24;i++){
			if(cloud>.99)break;
			vec3 planeCoord=wpos*((CLOUD_HEIGHT_END+(i+dither))/wpos.y)*.005*pow(cosT,-.1);
			vec2 coord=cameraPosition.xz*.00025+planeCoord.xz;
			float coverage=float(i-3.+dither)*.667;
			
			float noise=CloudNoiseEnd(coord,wind);
			noise=CloudCoverageEnd(noise,cosT,coverage)*noiseMultiplier;
			noise=noise/pow(pow(noise,2.5)+1.,.4);
			
			cloudGradient=mix(cloudGradient,
				mix(gradientMix*gradientMix,1.-noise,.25),
				noise*(1.-cloud*cloud));
				cloud=mix(cloud,1.,noise);
				gradientMix+=.6;
			}
			cloudcolor=lightCol*vec3(6.4,6.8,5.)*(1.+scattering)*pow(cloudGradient,.75);
			cloudcolor=pow(cloudcolor,vec3(2))*2*vec3(1.4,1.8,1.);
			cloud*=min(pow(cosT*2,2.),.42);
		}
		
		return vec4(cloudcolor*colorMultiplier*(.6+(pow(sunVisibility,.1))*.4),pow(cloud,2)*.1*CLOUD_OPACITY_END*(2-(pow(sunVisibility,.1))));
	}

		float GetNoise(vec2 pos){
		return fract(sin(dot(pos,vec2(12.9898,4.1414)))*43758.5453);
}

vec3 DrawStars(inout vec3 color,vec3 viewPos){
	vec3 wpos=vec3(gbufferModelViewInverse*vec4(viewPos,1.));
	vec3 planeCoord=wpos/(wpos.y+length(wpos.xz));
	planeCoord.x+=.399;
	planeCoord.z+=0.;
	vec2 wind=vec2(frametime,0.);
	vec2 coord=planeCoord.xz*DISTANCE_STARS+cameraPosition.xz*.0001+wind*.00125;
	coord=floor(coord*1024.)/1024.;
	
	float cosT=clamp(dot(normalize(viewPos), normalize(upVec)), 0.0, 1.0);
	float multiplier=sqrt(sqrt(cosT))*STARS_LIGHT_INTENSITY*(1.-rainStrength)*moonVisibility;
	
	float star=1.;
	if(cosT>0.){
		star*=GetNoise(coord.xy);
		star*=GetNoise(coord.xy+.115);
		star*=GetNoise(coord.xy+.230);
	}

	#if STARS_COVERAGE == 1
	float starsCov = 0.8125;
	#endif
	#if STARS_COVERAGE == 2
	float starsCov = 0.7125;
	#endif
	#if STARS_COVERAGE == 3
	float starsCov = 0.6125;
	#endif

	star=clamp(star - starsCov, 0.0, 1.0) * multiplier;
	
	color += star * pow(lightNight, vec3(0.8));
	return vec3(star);
}
	
	float AuroraNoise(vec2 coord,vec2 wind,float cosT ){
	float noise = texture2D(noisetex, coord * 0.0625  + wind * 0.25).b * 3.0;
		  noise+= texture2D(noisetex, coord * 0.03125 + wind * 0.15).b * 3.0;
		  noise = max(1.0 - 4.0 * (0.5 * cosT + 0.5) * abs(noise - 3.0), 0.0);

	return noise;
}
			
vec3 DrawShootingStar(vec3 clr,vec3 viewPos,float variation,float dither)
{
	#ifdef SHOOTING_STARS_AA
	#if AA>1
	dither=fract(16.*frameTimeCounter+dither);
	#endif
	#else
	dither=1.0;
	#endif

	float frameShootingStar = frameTimeCounter / SPEED_SHOOTING;
	float visibility=moonVisibility*(1.-rainStrength)*(1.-rainStrength);
    float sectime = mod(frameShootingStar,1.0);
    
    float lim1 = 59.0*variation;
    float lim2 = 69.0*variation;

    float time1 = mod(floor(frameShootingStar),lim1)/lim1;
    float time2 = mod(floor(frameShootingStar),lim2)/lim2;

    vec3 wpos=vec3(gbufferModelViewInverse*vec4(viewPos,1.));
    vec3 sstarpos1start = texture2D(noisetex,vec2(time1,time2)).rgb;
    sstarpos1start.xz = (sstarpos1start.xz * 2.0) - 1.0;
    vec3 sstarpos2start = texture2D(noisetex,vec2(1-time1,1-time2)).rgb;
    sstarpos2start.xz = (sstarpos2start.xz * 2.0) - 1.0;

	float isShooting = texture2D(noisetex,vec2 (time2,time1)).r;

    sstarpos1start = normalize(sstarpos1start);
    sstarpos2start = normalize(sstarpos2start);
    if(length(sstarpos1start-sstarpos2start) > 0.7 && visibility>0.0 && isShooting < SHOW_DELAY)
    {
		vec3 sstarpos1;
		vec3 sstarpos2;
		if(sectime < 0.5)
		{
			sstarpos1 = mix(sstarpos2start,sstarpos1start,sectime*2.0);
			sstarpos2 = sstarpos2start;
		}
		else
		{
			sstarpos1 = sstarpos1start;
			sstarpos2 = mix(sstarpos1start,sstarpos2start,(1.0-sectime)*2.0);
			
		}
			sstarpos1 = normalize(sstarpos1);
			sstarpos2 = normalize(sstarpos2);
			wpos = normalize(wpos);

		float l1=length(sstarpos1-wpos);
		float l2=length(sstarpos2-wpos);
		float l3=length(sstarpos1-sstarpos2);
		if (l3<STAR_THICKNESS)l3 = STAR_THICKNESS;
		float l4=length(((sstarpos1+sstarpos2)/2.0) - wpos);

		vec3 ss3 = cross(sstarpos1,sstarpos2);
		ss3 = normalize(ss3);
		float dist = dot(wpos,ss3);
		
		if (dist < 0 ) dist = -dist;
		if ((dist < STAR_THICKNESS && l3>l1  && l3>l2) || l1 < STAR_THICKNESS)
		{

			float t1 = 1.0-(dist / STAR_THICKNESS);
			float t2 = 1.0 -(l1 / l3);
			t2 = pow(t2,SHOOTING_STARS_FADE);
			float t = t1*t2*dither;
			float fade = clamp((1.0 - sectime), 0.0, 1.0);
			fade = clamp(pow(fade,15.0) * 600.0, 0.0, 1.0);
			clr = mix(clr,vec3 (1.0),t * fade);
		}
    }
    return clr;
}

vec3 DrawAurora(vec3 viewPos,float dither,int sampleCount){
	
	#if AA>1
	dither=fract(16.*frameTimeCounter+dither);
	#endif
	
	float gradientMix=dither/sampleCount;
	float cosT=dot(normalize(viewPos),upVec);
	float visibility=moonVisibility*(1.-rainStrength)*(1.-rainStrength);
	
	#ifndef AURORA_WEATHER_PERBIOME
	visibility *= isCold * isCold;
	#endif

	vec2 wind=vec2(
		frametime*CLOUD_SPEED*.000125,
		sin(frametime*CLOUD_SPEED*.05)*.00025
	);
	
	vec3 aurora=vec3(0.);
	
	if(cosT>0.&&visibility>0.){
		vec3 wpos=normalize((gbufferModelViewInverse*vec4(viewPos,1.)).xyz);
		for(int i=0;i<sampleCount;i++){
			vec3 planeCoord=wpos*((AURORA_DISTANCE+(i+dither)*AURORA_SIZE/sampleCount)/wpos.y)*.004;
			vec2 coord=cameraPosition.xz*.00004+planeCoord.xz;
			coord+=vec2(coord.y,-coord.x)*.3;
			
			float noise=AuroraNoise(coord,wind,cosT);
			
			if(noise>0.){
				noise*=texture2D(noisetex,coord*.125+wind*.25).b;
				noise*=.5*texture2D(noisetex,coord+wind*16.).b+.75;
				noise=noise*noise*3./sampleCount;
				noise*=max(sqrt(1.-length(planeCoord.xz)*3.75),0.);
				
				#if AURORA_COLOR == 1
				vec3 auroraColor=mix(
					vec3(.1,1.,.5),
					vec3(0.3451, 0.0, 0.4118),
					pow(gradientMix,.4)
				);
				#endif
				#if AURORA_COLOR == 2
				vec3 auroraColor=mix(
					vec3(.1,1.,.5),
					vec3(0.0, 0.0, 0.7216),
					pow(gradientMix,.4)
				);
				#endif
				#if AURORA_COLOR == 3
				vec3 auroraColor=mix(
					vec3(.1,1.,.5),
					vec3(0.6667, 0.0, 0.0),
					pow(gradientMix,.4)
				);
				#endif
				#if AURORA_COLOR == 4
				vec3 auroraColor=mix(
					vec3(.1,1.,.5),
					vec3(0.6157, 0.6275, 0.0),
					pow(gradientMix,.4)
				);
				#endif
				aurora+=noise*auroraColor*exp2(-6.*i/sampleCount);
			}
			gradientMix+=1./sampleCount;
		}
	}
	
	return aurora*visibility;
}