vec2 biomeRefraction(vec2 coord) {

	#ifdef BURNING_EFFECT
		const float refractionBurningMultiplier = BURNING_STRENGTH_REFRACT;
		float burningVisibility = 1.0;
		burningVisibility *= burningSmooth;
	#endif

	#if defined (NETHER) && defined NETHER_REFRACT
		const float refractionNetherMultiplier = STRENGTH_REFRACT;

		float heatNetherVisibility = 1.0;

		#if NETHER_WEATHER_HEAT == 1
			heatNetherVisibility *= biomeHasHeatSmooth3;
		#endif

		if (heatNetherVisibility < 0.1) {
			heatNetherVisibility = 0.0;
		}
	#endif

	#if defined (OVERWORLD) && defined DESERT_REFRACT

		const float refractionDesertMultiplier = STRENGTH_DESERT_REFRACT;

		float heatSmooth = biomeHasHeatSmooth;

		float heatDesertVisibility = clamp01(pow(eBS, 4.0));
		#if DESERT_WEATHER_HEAT == 1
			heatDesertVisibility *= heatSmooth * sunVisibility * (1.0 - rainStrength);
		#elif DESERT_WEATHER_HEAT == 2
			heatDesertVisibility *= heatSmooth * sunVisibility;
		#elif DESERT_WEATHER_HEAT == 3
			heatDesertVisibility *= heatSmooth * (1.0 - rainStrength);
		#elif DESERT_WEATHER_HEAT == 4
			heatDesertVisibility *= heatSmooth;
		#endif
		if (heatDesertVisibility < 0.1) {
			heatDesertVisibility = 0.0;
		}
	#endif

	#if defined (OVERWORLD) && defined MESA_REFRACT
		const float refractionMesaMultiplier = STRENGTH_MESA_REFRACT;

		float heatSmooth2 = biomeHasHeatSmooth2;

		float heatMesaVisibility = clamp01(pow(eBS, 4.0));
						#if MESA_WEATHER_HEAT == 1
		heatMesaVisibility *= heatSmooth2 * sunVisibility * (1.0 - rainStrength);
						#elif MESA_WEATHER_HEAT == 2
		heatMesaVisibility *= heatSmooth2 * sunVisibility;
						#elif MESA_WEATHER_HEAT == 3
		heatMesaVisibility *= heatSmooth2 * (1.0 - rainStrength);
						#elif MESA_WEATHER_HEAT == 4
		heatMesaVisibility *= heatSmooth2;
						#endif
		if (heatMesaVisibility < 0.1) {
			heatMesaVisibility = 0.0;
		}
	#endif

	#ifdef BURNING_EFFECT
	if (burningVisibility >= 0.1) {
		vec2 aspectcorrectBurn = vec2(aspectRatio, 1.0);

		float noiseBurn = texture2D(noisetex, coord.st * aspectcorrectBurn * 0.008 - vec2(0.0, frameTimeCounter * 0.009)).x;
		noiseBurn += texture2D(noisetex, coord.st * aspectcorrectBurn * 0.007 - vec2(0.0, frameTimeCounter * 0.009)).x;
		float burningRefrac = clamp01((noiseBurn - 1.0) * 4.0);
		coord -= vec2(0.0, coord.y) * refractionBurningMultiplier * burningRefrac * burningVisibility;

		noiseBurn = texture2D(noisetex, coord.st * aspectcorrectBurn * 0.007 - vec2(0.0, frameTimeCounter * 0.008)).x;
		noiseBurn += texture2D(noisetex, coord.st * aspectcorrectBurn * 0.006 - vec2(0.0, frameTimeCounter * 0.008)).x;
		burningRefrac = clamp01((noiseBurn - 1.0) * 4.0);
		coord -= vec2(0.0, coord.y) * refractionBurningMultiplier * burningRefrac * burningVisibility;

		noiseBurn = texture2D(noisetex, coord.st * aspectcorrectBurn * 0.006 - vec2(0.0, frameTimeCounter * 0.007)).x;
		noiseBurn += texture2D(noisetex, coord.st * aspectcorrectBurn * 0.005 - vec2(0.0, frameTimeCounter * 0.007)).x;
		burningRefrac = clamp01((noiseBurn - 1.0) * 4.0);
		coord -= vec2(0.0, coord.y) * refractionBurningMultiplier * burningRefrac * burningVisibility;

		noiseBurn = texture2D(noisetex, coord.st * aspectcorrectBurn * 0.005 - vec2(0.0, frameTimeCounter * 0.006)).x;
		noiseBurn += texture2D(noisetex, coord.st * aspectcorrectBurn * 0.004 - vec2(0.0, frameTimeCounter * 0.006)).x;
		burningRefrac = clamp01((noiseBurn - 1.0) * 4.0);
		coord -= vec2(0.0, coord.y) * refractionBurningMultiplier * burningRefrac * burningVisibility;

		noiseBurn = texture2D(noisetex, coord.st * aspectcorrectBurn * 0.004 - vec2(0.0, frameTimeCounter * 0.005)).x;
		noiseBurn += texture2D(noisetex, coord.st * aspectcorrectBurn * 0.003 - vec2(0.0, frameTimeCounter * 0.005)).x;
		burningRefrac = clamp01((noiseBurn - 1.0) * 4.0);
		coord -= vec2(0.0, coord.y) * refractionBurningMultiplier * burningRefrac * burningVisibility;

		noiseBurn = texture2D(noisetex, coord.st * aspectcorrectBurn * 0.003 - vec2(0.0, frameTimeCounter * 0.004)).x;
		noiseBurn += texture2D(noisetex, coord.st * aspectcorrectBurn * 0.002 - vec2(0.0, frameTimeCounter * 0.004)).x;
		burningRefrac = clamp01((noiseBurn - 1.0) * 4.0);
		coord -= vec2(0.0, coord.y) * refractionBurningMultiplier * burningRefrac * burningVisibility;

		noiseBurn = texture2D(noisetex, coord.st * aspectcorrectBurn * 0.002 - vec2(0.0, frameTimeCounter * 0.003)).x;
		noiseBurn += texture2D(noisetex, coord.st * aspectcorrectBurn * 0.001 - vec2(0., frameTimeCounter * 0.003)).x;
		burningRefrac = clamp01((noiseBurn - 1.0) * 4.0);
		coord -= vec2(0.0, coord.y) * refractionBurningMultiplier * burningRefrac * burningVisibility;
	}
	#endif

	#if defined (NETHER) && defined NETHER_REFRACT
	if (heatNetherVisibility >= 0.1) {
		vec2 aspectcorrectNether = vec2(aspectRatio, 1.0);

		float noiseNether = texture2D(noisetex, coord.st * aspectcorrectNether * 0.008 - vec2(0.0, frameTimeCounter * 0.007)).x;
		noiseNether += texture2D(noisetex, coord.st * aspectcorrectNether * 0.007 - vec2(0.0, frameTimeCounter * 0.007)).x;
		float netherfrac = clamp01((noiseNether - 1.) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionNetherMultiplier * netherfrac * heatNetherVisibility;

		noiseNether = texture2D(noisetex, coord.st * aspectcorrectNether * 0.007 - vec2(0.0, frameTimeCounter * 0.006)).x;
		noiseNether += texture2D(noisetex, coord.st * aspectcorrectNether * 0.006 - vec2(0.0, frameTimeCounter * 0.006)).x;
		netherfrac = clamp01((noiseNether - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionNetherMultiplier * netherfrac * heatNetherVisibility;

		noiseNether = texture2D(noisetex, coord.st * aspectcorrectNether * 0.006 - vec2(0.0, frameTimeCounter * 0.005)).x;
		noiseNether += texture2D(noisetex, coord.st * aspectcorrectNether * 0.005 - vec2(0.0, frameTimeCounter * 0.003)).x;
		netherfrac = clamp01((noiseNether - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionNetherMultiplier * netherfrac * heatNetherVisibility;

		noiseNether = texture2D(noisetex, coord.st * aspectcorrectNether * 0.005 - vec2(0.0, frameTimeCounter * 0.004)).x;
		noiseNether += texture2D(noisetex, coord.st * aspectcorrectNether * 0.004 - vec2(0.0, frameTimeCounter * 0.004)).x;
		netherfrac = clamp01((noiseNether - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionNetherMultiplier * netherfrac * heatNetherVisibility;

		noiseNether = texture2D(noisetex, coord.st * aspectcorrectNether * 0.004 - vec2(0.0, frameTimeCounter * 0.003)).x;
		noiseNether += texture2D(noisetex, coord.st * aspectcorrectNether * 0.003 - vec2(0.0, frameTimeCounter * 0.003)).x;
		netherfrac = clamp01((noiseNether - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionNetherMultiplier * netherfrac * heatNetherVisibility;

		noiseNether = texture2D(noisetex, coord.st * aspectcorrectNether * 0.003 - vec2(0.0, frameTimeCounter * 0.002)).x;
		noiseNether += texture2D(noisetex, coord.st * aspectcorrectNether * 0.002 - vec2(0.0, frameTimeCounter * 0.002)).x;
		netherfrac = clamp01((noiseNether - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionNetherMultiplier * netherfrac * heatNetherVisibility;

		noiseNether = texture2D(noisetex, coord.st * aspectcorrectNether * 0.002 - vec2(0.0, frameTimeCounter * 0.001)).x;
		noiseNether += texture2D(noisetex, coord.st * aspectcorrectNether * 0.001 - vec2(0.0, frameTimeCounter * 0.001)).x;
		netherfrac = clamp01((noiseNether - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionNetherMultiplier * netherfrac * heatNetherVisibility;
	}
	#endif

	#if defined (OVERWORLD) && defined DESERT_REFRACT
	if (heatDesertVisibility >= 0.1) {
		vec2 aspectcorrectDesert = vec2(aspectRatio, 1.0);

		float noiseDesert = texture2D(noisetex, coord.st * aspectcorrectDesert * 0.009 - vec2(0.0, frameTimeCounter * 0.009)).x;
		noiseDesert += texture2D(noisetex, coord.st * aspectcorrectDesert * 0.008 - vec2(0.0, frameTimeCounter * 0.009)).x;
		float desertfrac = clamp01((noiseDesert - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionDesertMultiplier * desertfrac * heatDesertVisibility;

		noiseDesert = texture2D(noisetex, coord.st * aspectcorrectDesert * 0.008 - vec2(0.0, frameTimeCounter * 0.008)).x;
		noiseDesert += texture2D(noisetex, coord.st * aspectcorrectDesert * 0.007 - vec2(0.0, frameTimeCounter * 0.008)).x;
		desertfrac = clamp01((noiseDesert - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionDesertMultiplier * desertfrac * heatDesertVisibility;

		noiseDesert = texture2D(noisetex, coord.st * aspectcorrectDesert * 0.007 - vec2(0.0, frameTimeCounter * 0.007)).x;
		noiseDesert += texture2D(noisetex, coord.st * aspectcorrectDesert * 0.006 - vec2(0.0, frameTimeCounter * 0.007)).x;
		desertfrac = clamp01((noiseDesert - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionDesertMultiplier * desertfrac * heatDesertVisibility;

		noiseDesert = texture2D(noisetex, coord.st * aspectcorrectDesert * 0.006 - vec2(0.0, frameTimeCounter * 0.006)).x;
		noiseDesert += texture2D(noisetex, coord.st * aspectcorrectDesert * 0.005 - vec2(0.0, frameTimeCounter * 0.006)).x;
		desertfrac = clamp01((noiseDesert - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionDesertMultiplier * desertfrac * heatDesertVisibility;

		noiseDesert = texture2D(noisetex, coord.st * aspectcorrectDesert * 0.005 - vec2(0.0, frameTimeCounter * 0.005)).x;
		noiseDesert += texture2D(noisetex, coord.st * aspectcorrectDesert * 0.004 - vec2(0.0, frameTimeCounter * 0.005)).x;
		desertfrac = clamp01((noiseDesert - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionDesertMultiplier * desertfrac * heatDesertVisibility;

		noiseDesert = texture2D(noisetex, coord.st * aspectcorrectDesert * 0.004 - vec2(0.0, frameTimeCounter * 0.004)).x;
		noiseDesert += texture2D(noisetex, coord.st * aspectcorrectDesert * 0.003 - vec2(0.0, frameTimeCounter * 0.004)).x;
		desertfrac = clamp01((noiseDesert - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionDesertMultiplier * desertfrac * heatDesertVisibility;

		noiseDesert = texture2D(noisetex, coord.st * aspectcorrectDesert * 0.003 - vec2(0.0, frameTimeCounter * 0.003)).x;
		noiseDesert += texture2D(noisetex, coord.st * aspectcorrectDesert * 0.002 - vec2(0.0, frameTimeCounter * 0.003)).x;
		desertfrac = clamp01((noiseDesert - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionDesertMultiplier * desertfrac * heatDesertVisibility;

		noiseDesert = texture2D(noisetex, coord.st * aspectcorrectDesert * 0.002 - vec2(0.0, frameTimeCounter * 0.002)).x;
		noiseDesert += texture2D(noisetex, coord.st * aspectcorrectDesert * 0.001 - vec2(0.0, frameTimeCounter * 0.002)).x;
		desertfrac = clamp01((noiseDesert - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionDesertMultiplier * desertfrac * heatDesertVisibility;
	}
	#endif

	#if defined (OVERWORLD) && defined MESA_REFRACT
	if (heatMesaVisibility >= 0.1) {
		vec2 aspectcorrectMesa = vec2(aspectRatio, 1.0);

		float noiseMesa = texture2D(noisetex, coord.st * aspectcorrectMesa * 0.009 - vec2(0.0, frameTimeCounter * 0.009)).x;
		noiseMesa += texture2D(noisetex, coord.st * aspectcorrectMesa * 0.008 - vec2(0.0, frameTimeCounter * 0.009)).x;
		float mesafrac = clamp01((noiseMesa - 1.) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionMesaMultiplier * mesafrac * heatMesaVisibility;

		noiseMesa = texture2D(noisetex, coord.st * aspectcorrectMesa * 0.008 - vec2(0.0, frameTimeCounter * 0.008)).x;
		noiseMesa += texture2D(noisetex, coord.st * aspectcorrectMesa * 0.007 - vec2(0.0, frameTimeCounter * 0.008)).x;
		mesafrac = clamp01((noiseMesa - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionMesaMultiplier * mesafrac * heatMesaVisibility;

		noiseMesa = texture2D(noisetex, coord.st * aspectcorrectMesa * 0.007 - vec2(0.0, frameTimeCounter * 0.007)).x;
		noiseMesa += texture2D(noisetex, coord.st * aspectcorrectMesa * 0.006 - vec2(0.0, frameTimeCounter * 0.007)).x;
		mesafrac = clamp01((noiseMesa - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionMesaMultiplier * mesafrac * heatMesaVisibility;

		noiseMesa = texture2D(noisetex, coord.st * aspectcorrectMesa * 0.006 - vec2(0.0, frameTimeCounter * 0.006)).x;
		noiseMesa += texture2D(noisetex, coord.st * aspectcorrectMesa * 0.005 - vec2(0.0, frameTimeCounter * 0.006)).x;
		mesafrac = clamp01((noiseMesa - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionMesaMultiplier * mesafrac * heatMesaVisibility;

		noiseMesa = texture2D(noisetex, coord.st * aspectcorrectMesa * 0.005 - vec2(0.0, frameTimeCounter * 0.005)).x;
		noiseMesa += texture2D(noisetex, coord.st * aspectcorrectMesa * 0.004 - vec2(0.0, frameTimeCounter * 0.005)).x;
		mesafrac = clamp01((noiseMesa - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionMesaMultiplier * mesafrac * heatMesaVisibility;

		noiseMesa = texture2D(noisetex, coord.st * aspectcorrectMesa * 0.004 - vec2(0.0, frameTimeCounter * 0.004)).x;
		noiseMesa += texture2D(noisetex, coord.st * aspectcorrectMesa * 0.003 - vec2(0.0, frameTimeCounter * 0.004)).x;
		mesafrac = clamp01((noiseMesa - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionMesaMultiplier * mesafrac * heatMesaVisibility;

		noiseMesa = texture2D(noisetex, coord.st * aspectcorrectMesa * 0.003 - vec2(0.0, frameTimeCounter * 0.003)).x;
		noiseMesa += texture2D(noisetex, coord.st * aspectcorrectMesa * 0.002 - vec2(0.0, frameTimeCounter * 0.003)).x;
		mesafrac = clamp01((noiseMesa - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionMesaMultiplier * mesafrac * heatMesaVisibility;

		noiseMesa = texture2D(noisetex, coord.st * aspectcorrectMesa * 0.002 - vec2(0.0, frameTimeCounter * 0.002)).x;
		noiseMesa += texture2D(noisetex, coord.st * aspectcorrectMesa * 0.001 - vec2(0.0, frameTimeCounter * 0.002)).x;
		mesafrac = clamp01((noiseMesa - 1.0) * 5.0);
		coord -= vec2(0.0, coord.y) * refractionMesaMultiplier * mesafrac * heatMesaVisibility;
	}
	#endif

	return coord;
}