Shader "URP/Environment/Sky&Fog/AtmosphericScattering"
{
	Properties 
	{
		//_MainTex("Base (RGB)", 2D) = "white" {}
		[NoScaleOffset]_MoonTex ("Moon",2D) = "black" {}
		[NoScaleOffset]_BackgroundTexture("Backgroud", 2D) = "black" {}
		//_BackgroudOffset("BackgroudOffset", Vector) = (0 ,0, 0, 0)
		//_BackgroudRotation("BackgroudRotation", Range(0, 360)) = 0
	}

	HLSLINCLUDE

	#pragma target 3.0
	#pragma multi_compile _ _MILKY_WAY_ON

	#include "AtmosphericScattering/Atmosphere.hlsl"
	#include "AtmosphericScattering/PostEffect.hlsl"


				
	TEXTURE2D(_BackgroundTexture);	SAMPLER(sampler_BackgroundTexture);
	TEXTURE2D(_MainTex);	SAMPLER(sampler_MainTex);
	float4		_MainTex_TexelSize;

	struct appdata_img
	{
		float4 vertex : POSITION;
		float2 texcoord : TEXCOORD0;
		UNITY_VERTEX_INPUT_INSTANCE_ID
	};

	struct v2f 
	{
		float4 pos				: SV_POSITION;
		float2 uv				: TEXCOORD0;
		float2 clip_pos			: TEXCOORD1;
		float3 interpolatedRay 	: TEXCOORD3;
	};
	

	v2f VS_Sky( appdata_img v )
	{
		v2f o;
		half index = v.vertex.z;
		v.vertex.z = 0.1;
		o.pos = float4(v.vertex.xy, 1, 1);//TransformObjectToHClip(v.vertex.xyz);
		//o.pos.w = 1;

#if UNITY_UV_STARTS_AT_TOP
		v.texcoord = v.texcoord * float2(1.0, -1.0) + float2(0.0, 1.0);
#endif
		o.uv = UnityStereoTransformScreenSpaceTex(v.texcoord.xy);
		o.clip_pos = v.vertex.xy;
														
		o.interpolatedRay = FrustumCorners((int)index);
		
		return o;
	}

	float3 _BackgroudOffset;
	float _BackgroudRotation;
	half4 BackgroundLatLongSphere(float3 view)
	{
		float alpha = _BackgroudRotation * PI / 180.0;
		float sina, cosa;
		sincos(alpha, sina, cosa);
		float2x2 m = float2x2(cosa, -sina, sina, cosa);
		view =  float3(mul(m, view.xz), view.y).xzy;

		// Plate-carree projection:
		float ang = atan2(view.y, -view.x);
		float t = ang / (PI/**2.0*/);
		float t1 = frac(t) * 2.0;
		float2 lat_long_texc = float2(t1, 0.5 - asin(view.z) / PI);
		lat_long_texc.y = lat_long_texc.y * 2 - 0.5;
		half4 result1 = SAMPLE_TEXTURE2D(_BackgroundTexture, sampler_BackgroundTexture, lat_long_texc);
		return backgourdBrightness*result1;
	}

	half4 PS_Sky( v2f i ) : SV_Target
	{
		half4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);

		float rawDepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.uv);

		float depth = LinearEyeDepth(rawDepth, _ZBufferParams);
		depth = DepthToFadeDistance(depth, i.clip_pos.xy);

		float3 viewDir = normalize(i.interpolatedRay.xyz);

		half3 backgound = float3(0, 0, 0);
#ifdef _MILKY_WAY_ON

#if UNITY_REVERSED_Z
		if (rawDepth < 0.0000001f)
#else
		if (rawDepth > 0.9999999f)
#endif
			sceneColor += BackgroundLatLongSphere(viewDir);
	
#endif

		float3 cameraToWorldPos = viewDir * depth;
		float3 worldPos = _WorldSpaceCameraPos + cameraToWorldPos;
		half3 OutColor = ApplyAtmosphericScattering(sceneColor, worldPos, viewDir);


		
		return half4(OutColor, sceneColor.a);
	}
	

	struct v2fSunAndMoon
	{
		float4 pos				: SV_POSITION;
		float2 tex				: TEXCOORD0;
		//float4 clip_pos			: TEXCOORD1;
	};
	
	v2fSunAndMoon VS_Sun( appdata_img v )
	{
		v2fSunAndMoon o;
		
		//float3 pos = float3(v.vertex.xy, 1.0 / glowRadiusMultiple / tan(radiusRadians));
		float3 pos = float3(0, 0, 1.0 / glowRadiusMultiple / tan(radiusRadians));
		o.pos = TransformObjectToHClip(pos.xyz);
		
		o.pos.xy += v.vertex.xy * float2(UNITY_MATRIX_P[0][0], UNITY_MATRIX_P[1][1]) * UNITY_MATRIX_MVP[3][2];

#if UNITY_REVERSED_Z
		o.pos.z = 0;
#else
		o.pos.z = o.pos.w;
#endif
		o.tex = glowRadiusMultiple*v.vertex.xy;
		//o.clip_pos = o.pos.xyzw;
		//// Prevent clipping:
		//if (o.clip_pos.z<0)
		//	o.clip_pos.z = 0;
		//if (o.clip_pos.z>o.clip_pos.w)
		//	o.clip_pos.z = o.clip_pos.w;
		
		return o;
	}

	float4 PS_Sun(v2fSunAndMoon IN) : SV_Target
	{
		//return float4(1,0,0,1);
		float r = length(IN.tex);
		if (r>glowRadiusMultiple)
			discard;
		float brightness = step(r,1.0)*sunBrightness;
		brightness *= saturate((0.97 - r) / 0.03);
		float sine = 0.0;
		// ����loss���ֵ����̫����С
		float4 loss_lookup = SAMPLE_TEXTURE2D(loss_2d_texture, sampler_loss_2d_texture, float2(1.0, min(0.4, 0.5*(1.0 - sine))));
		float most_loss = max(min(min(loss_lookup.r,loss_lookup.g),loss_lookup.b), 0.02);
		float to_zero = 1.0 / most_loss*saturate((glowRadiusMultiple - r) / (glowRadiusMultiple - 1.0));
		brightness = to_zero*max(brightness,glowBrightness / pow(max(1.0,r),4.0));
		float4 result = float4(brightness.xxx,1.0);

		return result;
	}


	v2fSunAndMoon VS_Moon( appdata_img v )
	{
		v2fSunAndMoon o;
		
		//float3 pos = float3(v.vertex.xy, 1.0 / moonGlowRadiusMultiple / tan(moonRadiusRadians));
		float3 pos = float3(0, 0, 1.0 / moonGlowRadiusMultiple / tan(moonRadiusRadians));
		o.pos = TransformObjectToHClip(pos.xyz);
		
		o.pos.xy += v.vertex.xy * float2(UNITY_MATRIX_P[0][0], UNITY_MATRIX_P[1][1]) * UNITY_MATRIX_MVP[3][2];

#if UNITY_REVERSED_Z
		o.pos.z = 0;
#else
		o.pos.z = o.pos.w;
#endif
		o.tex = moonGlowRadiusMultiple*v.vertex.xy;
		//o.clip_pos = o.pos.xyzw;
		//// Prevent clipping:
		//if (o.clip_pos.z<0)
		//	o.clip_pos.z = 0;
		//if (o.clip_pos.z>o.clip_pos.w)
		//	o.clip_pos.z = o.clip_pos.w;
		
		return o;
	}

	float adjustContrast(float brightness)
	{
		return 1.0 - pow(1.0 - brightness, moonBrightnessContrast);
	}

	float approx_oren_nayar(float roughness, float3 view, float3 normal, float3 lightDir)
	{
		float roughness2 = roughness * roughness;
		float2 oren_nayar_fraction = roughness2 / (float2(roughness2, roughness2) + float2(0.33, 0.09));
		float2 oren_nayar = float2(1, 0) + float2(-0.5, 0.45) * oren_nayar_fraction;
		// Theta and phi
		float2 cos_theta = saturate(float2(dot(normal, lightDir), dot(normal, view)));
		float2 cos_theta2 = cos_theta * cos_theta;
		float u = saturate((1 - cos_theta2.x) * (1 - cos_theta2.y));
		float sin_theta = sqrt(u);
		float3 light_plane = normalize(lightDir - cos_theta.x * normal);
		float3 view_plane = normalize(view - cos_theta.y * normal);
		float cos_phi = saturate(dot(light_plane, view_plane));
		// Composition
		float diffuse_oren_nayar = cos_phi * sin_theta / max(0.00001, max(cos_theta.x, cos_theta.y));

		cos_theta.x = adjustContrast(cos_theta.x);
		float diffuse = cos_theta.x * (oren_nayar.x + oren_nayar.y * diffuse_oren_nayar);
		return diffuse;
	}

	TEXTURE2D(_MoonTex); SAMPLER(sampler_MoonTex);
	float4 PS_Moon(v2fSunAndMoon IN) : SV_Target
	{
		//return float4(1,0,0,1);
		float4 result = SAMPLE_TEXTURE2D(_MoonTex, sampler_MoonTex, float2(0.5,0.5) - 0.5*IN.tex);
		float3 normal;
		normal.x = IN.tex.x;
		normal.y = IN.tex.y;
		float l = length(IN.tex);
		if (l>1.0)
			return float4(0.0, 0.0, 0.0, 0.0);

		normal.z = -sqrt(1.0 - l*l);

		float light = saturate(dot(normal, moonLightSrcDir));
		light = adjustContrast(light);
		result.rgb *= moonColor.rgb;
		result.rgb *= light;
		result.a *= saturate((0.97 - l) / 0.03);

		return result;
	}


	struct appdata_Sun {
		float4 vertex : POSITION;
		float4 texcoord : TEXCOORD0;
		float4 color : COLOR;
	};
	struct v2fStars
	{
		float4 pos	: SV_POSITION;
		float2 tex	: TEXCOORD0;
		half4 color	: TEXCOORD1;
	};

	float GetFlickerAmount(in float2 pos)
	{
		const float2 tab[8] =
		{
			float2(0.897907815,-0.347608525), float2(0.550299290, 0.273586675), float2(0.823885965, 0.098853070), float2(0.922739035,-0.122108860),
			float2(0.800630175,-0.088956800), float2(0.711673375, 0.158864420), float2(0.870537795, 0.085484560), float2(0.956022355,-0.058114540)
		};

		float2 hash = frac(pos.xy * 256);
		float index = frac(hash.x + (hash.y + 1) * (_Time.x * 2 + unity_DeltaTime.z)); // flickering speed
		index *= 8;

		float f = frac(index)* 2.5;
		int i = (int)index;

		// using default const tab array. 
		// occasionally this is not working for WebGL and some android build
		return tab[i].x + f * tab[i].y;
	}
	
	v2fStars VS_Stars(appdata_Sun v )
	{
		v2fStars o;
		
		o.pos = TransformObjectToHClip(v.vertex.xyz);
#if UNITY_REVERSED_Z
		o.pos.z = 0;
#else
		o.pos.z = o.pos.w;
#endif
		float appMag = 6.5 + v.color.w * (-1.44 - 1.5);
		float brightness = GetFlickerAmount(v.vertex.xz) * pow(5.0, (-appMag - 1.44) / 2.5);
		
		o.color = float4(v.color.xyz*brightness, brightness) * starBrightness;
		o.tex = 6.5 * v.texcoord.xy - 6.5 * float2(0.5, 0.5);
		return o;
	}

	half4 PS_Stars(v2fStars IN) : SV_Target
	{
		half2 distCenter = IN.tex.xy;
		half scale = exp(-dot(distCenter, distCenter));
		half3 col = IN.color.xyz * scale + 5 * IN.color.w * pow(scale, 10);
		col = (col*col) * 2;
		return half4(col, 1);
	}

ENDHLSL

//-----------------------------------------------

SubShader {
	// sky
	Pass {
		ZTest Always 
		Cull Off 
		ZWrite Off

		HLSLPROGRAM
		#pragma vertex VS_Sky
		#pragma fragment PS_Sky
		//#pragma enable_d3d11_debug_symbols

		ENDHLSL
	}
	// sun
	Pass {
		ZTest LEqual
		Cull Off 
		ZWrite Off
		Blend SrcAlpha One

		HLSLPROGRAM
		#pragma vertex VS_Sun
		#pragma fragment PS_Sun
		//#pragma enable_d3d11_debug_symbols

		ENDHLSL
	}
	// moon
	Pass {
		ZTest LEqual
		Cull Off 
		ZWrite Off
		Blend SrcAlpha One

		HLSLPROGRAM
		#pragma vertex VS_Moon
		#pragma fragment PS_Moon
		//#pragma enable_d3d11_debug_symbols

		ENDHLSL
	}

	// stars
	Pass {
		ZTest LEqual
		Cull Off 
		ZWrite Off
		Blend SrcAlpha One

		HLSLPROGRAM
		#pragma vertex VS_Stars
		#pragma fragment PS_Stars
		//#pragma enable_d3d11_debug_symbols

		ENDHLSL
	}
	

  }
 Fallback off
}
