vec4 DistortShadow(vec4 shadowpos, float distortFactor) {
	shadowpos.xy*=1.0 / distortFactor;
	shadowpos.z  =shadowpos.z * 0.2;
	shadowpos    =shadowpos * 0.5 + 0.5;

	return shadowpos;
}

void GetShadowSpace(inout vec3 worldposition, inout vec4 vlposition, float shadowdepth, vec2 texCoord) {
	vec4 viewPos =gbufferProjectionInverse * (vec4(texCoord, shadowdepth, 1.0) * 2.0 - 1.0);
	     viewPos/=viewPos.w;

	vec4 wpos          =gbufferModelViewInverse * viewPos;
	     worldposition =wpos.xyz / wpos.w;
	     wpos          =shadowModelView * wpos;
	     wpos          =shadowProjection * wpos;
	     wpos         /=wpos.w;

	float distb        =sqrt(wpos.x * wpos.x + wpos.y * wpos.y);
	float distortFactor=1.0 - shadowMapBias + distb * shadowMapBias;
	      wpos         =DistortShadow(wpos,distortFactor);

	#if defined WATER_CAUSTICS && defined OVERWORLD && defined SMOKEY_WATER_LIGHTSHAFTS
		if (isEyeInWater == 1.0) {
			vec3  worldPos   =ViewToWorld(viewPos.xyz);
			vec3  causticpos =worldPos.xyz + cameraPosition.xyz;
			float caustic    =getCausticWaves(causticpos.xyz * 0.25);
			      wpos.xy   *=1.0 + caustic * 0.0125;
		}
	#endif

	vlposition = wpos;
}

vec3 getVolumetricRays(float depth0, float depth1, vec3 vlAlbedo, float dither, float cosS) {
	vec3 vl = vec3(0.0);

	#if AA > 1
		dither = fract(dither + frameTimeCounter * 64.0);
	#endif

	#ifdef OVERWORLD
			float visibility = 0.055;

			if (isEyeInWater == 1) visibility = 0.19;

			float endurance = 1.0;

			if (isEyeInWater == 0) endurance *= min(2.0 + pow2(rainStrengthS)- pow2(sunVisibility), 2.0);
			else visibility *= 1.0 + 2.0 * pow(max(cosS, 0.0), 128.0) * float(sunVisibility > 0.5) * (1.0 - rainStrengthS);

			if (endurance >= 1.0) visibility *= max((cosS + endurance) / (endurance + 1.0), 0.0);
			else visibility *= pow(max((cosS + 1.0) / 2.0, 0.0), (11.0 - endurance * 10.0));

	#endif

		#ifdef END
			#ifdef LIGHT_SHAFT_END
				float visibility=0.14285;
			#else
				float visibility=0.0;
			#endif
		#endif


	if (visibility > 0.0) {

		#ifdef END
			float maxDist = 192.0 * (1.5 - isEyeInWater);
		#else
			float maxDist = 288.0;

			if (isEyeInWater == 1) maxDist = min(288.0, shadowDistance * 0.75);

		#endif

		vec3 worldposition = vec3(0.0);
		vec4 vlposition = vec4(0.0);

		#if (defined END || defined OVERWORLD) && UNDERWATER_LIGHT_SHAFT_COLOR_CUSTOM >= 0
		vec3 watercol=rawWaterColorSqrt.rgb / UNDERWATER_I;
		     watercol=pow(watercol * 1.0, vec3(2.3)) * 70.0;
		#endif

		#if defined OVERWORLD && UNDERWATER_LIGHT_SHAFT_COLOR_CUSTOM == 1
		vec3 watercol2=rawWaterColorLightshaft.rgb / UNDERWATER_LIGHT_SHAFT_I;
		     watercol2=pow(watercol2, vec3(2.3)) * 70.0;
		#endif

		#ifdef END
			float minDistFactor =5.0;
		#else
			float minDistFactor =11.0;

			if (moonVisibility >0.0){
			minDistFactor *= mix(1.0,clamp(far, 288.0, 512.0) / 192.0,moonVisibility);
			}
			if (sunVisibility >0.0){
			minDistFactor *= mix(1.0,clamp(far, 256.0, 512.0) / 192.0,sunVisibility);
			}

			float fovFactor = gbufferProjection[1][1] / 1.37;
			float x = abs(texCoord.x - 0.5);
			x = 1.0 - x*x;
			x = pow(x, max(3.0 - fovFactor, 0.0));
			minDistFactor *= x;
			maxDist *= x;

		#endif

		#ifdef END
			int sampleCount = 9;
		#else
			int sampleCount = 9;
			float addition = 0.5;

			if (isEyeInWater == 0) {
			sampleCount = 7;
			minDistFactor *= 0.5;
			}
			float sampleIntensity = LIGHT_SHAFT_SAMPLE_INTENSITY;

			#if LIGHT_SHAFT_QUALITY == 2
				if (isEyeInWater == 0) {
					float qualityFactor   =1.42857;
					      sampleCount     =6;
					      sampleIntensity/=qualityFactor;
					      minDistFactor  /=1.7;
					      addition       *=qualityFactor;
				}
			#endif

		#endif

		for(int i = 0; i < sampleCount; i++) {
			#ifdef END
				float minDist = exp2(i + dither) - 0.9;
			#else
				float minDist = 0.0;
				if (isEyeInWater == 0) {

					minDist = pow(i + dither + addition, 1.5) * minDistFactor;

				} else minDist = pow2(i + dither + 0.5) * minDistFactor * 0.045;
			#endif

			if (minDist >= maxDist) break;

			if (depth1 < minDist || (depth0 < minDist && vlAlbedo == vec3(0.0))) break;

			GetShadowSpace(worldposition, vlposition, GetDistX(minDist), texCoord.st);

			if (length(vlposition.xy * 2.0 - 1.0) < 1.0){

				float shadow0 = shadow2D(shadowtex0, vlposition.xyz).z;

				vec3 shadowCol = vec3(0.0);
				#ifdef COLORED_SHADOWS
				if (shadow0 < 1.0) {
					float shadow1 = shadow2D(shadowtex1, vlposition.xyz).z;
					if (shadow1 > 0.0) {
						shadowCol =texture(shadowcolor0, vlposition.xy).rgb;
						shadowCol*=shadowCol * shadow1;
					}
				}
				#endif

				vec3 shadow = clamp(shadowCol * (1.0 - shadow0) + shadow0, vec3(0.0), vec3(1.0));

				if (depth0 < minDist) shadow *= vlAlbedo;

				#if defined END && defined LIGHT_SHAFT_END
					#ifdef ENDER_SMOKER_LIGHT_SHAFT
					vec3  npos   =worldposition.xyz + cameraPosition.xyz + vec3(frameTimeCounter * ENDER_SMOKER_LIGHT_SHAFT_SPEED * 0.25, 0, 0);
					float n3da   =texture(noisetex, npos.xz / 512.0 + floor(npos.y / 3.0) * 0.35).r;
					float n3db   =texture(noisetex, npos.xz / 512.0 + floor(npos.y / 3.0 + 1.0) * 0.35).r;
					float noise  =mix(n3da, n3db, fract(npos.y / 3.0));
					      noise  =sin(noise * 28.0 + frameTimeCounter * ENDER_SMOKER_LIGHT_SHAFT_SPEED * 0.25) * 0.25 + 0.5;
					      shadow*=noise;
					#endif
				#endif

				#if defined OVERWORLD && defined LIGHT_SHAFT
					#if SMOKER_LIGHT_SHAFT > 0
						if (isEyeInWater == 0){
						vec3  npos =worldposition.xyz + cameraPosition.xyz + vec3(frameTimeCounter * SMOKER_LIGHT_SHAFT_OVERWORLD_SPEED*0.25, 0, 0);
						float n3da =texture(noisetex, npos.xz /512.0 + floor(npos.y / 3.0) * 0.35).r;
						float n3db =texture(noisetex, npos.xz / 512.0 + floor(npos.y / 3.0 + 1.0) * 0.35).r;
						float noise=mix(n3da, n3db, fract(npos.y / 3.0));
						      noise=sin(noise * 20.0 + frameTimeCounter *SMOKER_LIGHT_SHAFT_OVERWORLD_SPEED*0.25) * 0.25 + 0.5;
						#if SMOKER_LIGHT_SHAFT == 1
						noise = mix(1.0,noise,moonVisibility);
						#endif
						#if SMOKER_LIGHT_SHAFT == 2
						noise = mix(1.0,noise,rainStrengthS);
						#endif
						#if SMOKER_LIGHT_SHAFT == 3
						noise = mix(1.0,noise,1.0-((1.0-rainStrengthS)*(1.0-moonVisibility)));
						#endif
						shadow *= noise;
						}
					#endif
				#endif

				#ifdef END
					if (isEyeInWater == 1) shadow *= watercol.rgb;
					vl += shadow;
				#else
					if (isEyeInWater == 0) {
					vl += shadow * sampleIntensity;
					}else{

						#if UNDERWATER_LIGHT_SHAFT_COLOR_CUSTOM < 1
							shadow *= watercol * 0.5;
						#else
							shadow *= watercol2 * 0.5;
						#endif

					float sampleFactor = sqrt(minDist / maxDist);
					vl += shadow * sampleFactor * 0.55;
					}
				#endif
			} else {
				vl += 1.0;
			}
		}

		vl = sqrt(vl * visibility);


		if(isEyeInWater==1)	{
			vl /= sqrt(vl);
		}

		#if MC_VERSION >= 11800
			vl *= clamp01((cameraPosition.y + 70.0) / 8.0);
		#else
			vl *= clamp01((cameraPosition.y + 6.0) / 8.0);
		#endif

		#ifdef UNDERGROUND_SKY
			if (isEyeInWater<1){
				vl *= mix(clamp01((cameraPosition.y - 48.0) / 16.0), 1.0, eBS2);
			}
		#endif

			#ifdef END
			#else
				#ifdef LIGHT_SHAFT
					if (isEyeInWater == 0) {
						float vlPower = max(1.75 - rainStrengthS + sunVisibility * 0.25, 1.0);
						vl = pow(vl, vec3(vlPower));
					}
				#endif
			#endif

		vl *= 0.9;
		if (dot(vl, vl) > 0.0) vl += (dither - 0.19) / 256.0;
	}

	return vl;
}