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;
}

float CloudCoverage(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);
	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/15.;
		
		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+(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);
	}
	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*(.5-.25*(1.-sunVisibility)*(1.-rainStrength));
		float noiseMultiplier=CLOUD_THICKNESS*.15;
		float scattering=pow(cosS*.5+.5,6.);
		
		vec2 wind=vec2(frametime*CLOUD_SPEED*.005,
			sin(frametime*CLOUD_SPEED*.05)*.002)*CLOUD_HEIGHT/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+(i+dither))/wpos.y)*.005*pow(cosT,-.1);
					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+=.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*(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*.5+cameraPosition.xz*.001+wind*.00125;
			coord=floor(coord*1024.)/1024.;
			
			float cosT=clamp(dot(normalize(viewPos), normalize(upVec)), 0.0, 1.0);
			float multiplier=sqrt(sqrt(cosT))*5.*(1.-rainStrength)*moonVisibility;
			
			float star=1.;
			if(cosT>0.){
				star*=GetNoise(coord.xy);
				star*=GetNoise(coord.xy+.1);
				star*=GetNoise(coord.xy+.23);
			}
			star=clamp(star - 0.8125, 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 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*((8.+(i+dither)*7./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.);
							
							vec3 auroraColor=mix(
								vec3(.1,1.,.5),
								vec3(.1,.1,1.),
								pow(gradientMix,.4)
							);
							aurora+=noise*auroraColor*exp2(-6.*i/sampleCount);
						}
						gradientMix+=1./sampleCount;
					}
				}
				
				return aurora*visibility;
			}