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 + frameTimeCounter * 64.0);
	#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) * (5.0 * isEyeInWater + 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));
	float minDistFactor = 5.0;

	for(int i = 0; i < 14; i++) {
			float minDist = (exp2(i + dither) - 0.9) * minDistFactor;
			float breakFactor = 0.0;

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

				if (depth0 < minDist) shadow0 *= color;

				#if COLOR_WATER_MULTIPLIER ==1
				if (isEyeInWater == 1.0) shadow0 *= (watercol / WATER_POWER_COLOR) * WATER_LIGHTSHAFT_STRENGHT;
				#else
				#if COLOR_WATER_MULTIPLIER ==2
				if (isEyeInWater == 1.0) shadow0 *= (watercol * watercol) / WATER_POWER_COLOR * WATER_LIGHTSHAFT_STRENGHT;
				#endif
				#endif

				vl += shadow0;
			}
			else{
				vl += 1.0;
			}
			if (breakFactor > 0.5) break;
		}
		vl = vl * visibility;
		vl /= 0.25 + vl;
		if (dot(vl, vl) > 0.0) vl += (dither - 0.25) / 256.0;
	}
	
	return vl;
}