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