float distx(float dist){
	return(far*(dist-near))/(dist*(far-near));
}

float getDepth(float depth){
	return 2.*near*far/(far+near-(2.*depth-1.)*(far-near));
}

vec4 distortShadow(vec4 shadowpos,float distortFactor){
	shadowpos.xy*=1./distortFactor;
	shadowpos.z=shadowpos.z*.2;
	shadowpos=shadowpos*.5+.5;
	
	return shadowpos;
}

vec4 getShadowSpace(float shadowdepth,vec2 texCoord){
	vec4 viewPos=gbufferProjectionInverse*(vec4(texCoord,shadowdepth,1.)*2.-1.);
	viewPos/=viewPos.w;
	
	vec4 wpos=gbufferModelViewInverse*viewPos;
	wpos=shadowModelView*wpos;
	wpos=shadowProjection*wpos;
	wpos/=wpos.w;
	
	float distb=sqrt(wpos.x*wpos.x+wpos.y*wpos.y);
	float distortFactor=1.-shadowMapBias+distb*shadowMapBias;
	wpos=distortShadow(wpos,distortFactor);
	
	return wpos;
}

//Volumetric light from Robobo1221 (modified)
vec3 getVolumetricRays(float pixeldepth0,float pixeldepth1,vec3 color,float dither){
	vec3 vl=vec3(0.);
	
	#if AA > 1
	dither=fract(dither+frameCounter/32.);
	#endif
	
	vec3 screenPos = vec3(texCoord, pixeldepth0);
	vec4 viewPos = gbufferProjectionInverse * (vec4(screenPos, 1.0) * 2.0 - 1.0);
	viewPos /= viewPos.w;
	
	#ifdef OVERWORLD
	vec3 lightVec = sunVec * ((timeAngle < 0.5325 || timeAngle > 0.9675) ? 1.0 : -1.0);
	float VoL = dot(normalize(viewPos.xyz), lightVec);
	float visfactor = 0.05 * (-0.8 * timeBrightness + 1.0) * (3.0 * rainStrength + 1.0);
	float invvisfactor = 1.0 - visfactor;
	
	float visibility = clamp(VoL * 0.5 + 0.5, 0.0, 1.0);
	visibility = visfactor / (1.0 - invvisfactor * visibility) - visfactor;
	visibility = clamp(visibility * 1.015 / invvisfactor - 0.015, 0.0, 1.0);
	visibility = mix(1.0, visibility, 0.25 * eBS + 0.75) * 0.14285 * float(pixeldepth0 > 0.56);
	#endif

#ifdef END
#ifdef LIGHTSHAFT_END
float visibility=.14285* float(pixeldepth0 > 0.56);
#else
float visibility=0;
#endif
#endif

if(visibility>0.){
	float maxDist=LIGHT_SHAFT_DIST;
	
	float depth0=getDepth(pixeldepth0);
	float depth1=getDepth(pixeldepth1);
	vec4 worldposition=vec4(0.);
	
	vec3 watercol = mix(vec3(1.0), waterColor.rgb / sqrt(waterColor.a), pow(waterAlpha, 0.25));
	
	for(int i = 0; i < 7; i++) {
			float minDist = exp2(i + dither) - 0.9;
			if (minDist >= maxDist) break;

			if (depth1 < minDist || (depth0 < minDist && color == vec3(0.0))) {
				break;
			}
		
		worldposition=getShadowSpace(distx(minDist),texCoord.st);
		worldposition.z+=.00002;
		
		if (length(worldposition.xy * 2.0 - 1.0) < 1.0) {
				float shadow0 = shadow2D(shadowtex0, worldposition.xyz).z;
				
				vec3 shadowCol = vec3(0.0);
				#ifdef SHADOW_COLOR
				if (shadow0 < 1.0) {
					float shadow1 = shadow2D(shadowtex1, worldposition.xyz).z;
					if (shadow1 > 0.0) {
						shadowCol = texture2D(shadowcolor0, worldposition.xy).rgb;
						shadowCol *= shadowCol * shadow1;
					}
				}
			#endif
			vec3 shadow = clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(1.0));

				if (depth0 < minDist) shadow *= color;
				else if (isEyeInWater == 1.0) shadow *= watercol * 0.5;

				vl += shadow;
			}
			else{
				vl += 1.0;
			}
		}
		vl = vl * visibility;
		vl /= 0.25 + vl;
		if (dot(vl, vl) > 0.0)
		vl += (dither - 0.25) / 128.0;
	}
	
	return vl;
}