shader_type spatial;

render_mode unshaded, depth_test_disabled, cull_disabled;

uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;
uniform sampler2D noise_texture : repeat_enable, filter_linear;

uniform float cloud_scale : hint_range(0.001, 0.2) = 0.05;
uniform float cloud_speed : hint_range(0.0, 1.0) = 0.05;
uniform vec2 direction = vec2(1.0, 0.2);
uniform vec2 sun_angle = vec2(0.5, 0.5);

group_uniforms Cloud_Shape;
uniform float cloud_density : hint_range(0.0, 1.0) = 0.5;
uniform float center_sharpness : hint_range(0.0, 0.99) = 0.7;

group_uniforms Layout;
uniform vec3 shadow_color : source_color = vec3(0.0, 0.0, 0.0);
uniform float opacity_center : hint_range(0.0, 1.0) = 0.5;
uniform float opacity_edge : hint_range(0.0, 1.0) = 0.2;

group_uniforms Fade_Distance;
//Fade based on camera distance
uniform float fade_start : hint_range(10.0, 1000.0) = 150.0; 
uniform float fade_end : hint_range(50.0, 2000.0) = 300.0;   

group_uniforms Fade_Height;
//Fade based on base height (Y) - meters
uniform float height_fade_start : hint_range(0.0, 500.0) = 10.0; //start disappear at 10m
uniform float height_fade_end : hint_range(0.0, 1000.0) = 50.0;  //disappear over 50m

void vertex() {
	POSITION = vec4(VERTEX.xy, 1.0, 1.0);
}

void fragment() {
	float depth = texture(depth_texture, SCREEN_UV).x;

	if (depth >= 0.9999) {
		ALPHA = 0.0; 
	} else {
		vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth);
		vec4 view_pos = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
		view_pos /= view_pos.w;
		vec4 world_pos = INV_VIEW_MATRIX * view_pos;

		float dist = length(view_pos.xyz);
		float dist_fade = smoothstep(fade_end, fade_start, dist);

		float height_fade = smoothstep(height_fade_end, height_fade_start, world_pos.y);

		float final_fade = dist_fade * height_fade;

		if (final_fade <= 0.001) {
			ALPHA = 0.0;
		} else {
			vec2 projected_xz = world_pos.xz + (world_pos.y * sun_angle);
			vec2 uv = projected_xz * cloud_scale;
			uv += TIME * cloud_speed * direction;

			float n = texture(noise_texture, uv).r;

			if (n < (1.0 - cloud_density)) {
				ALPHA = 0.0;
			} else {
				float internal_n = (n - (1.0 - cloud_density)) / cloud_density;
				float is_center = step(center_sharpness, internal_n);

				ALBEDO = shadow_color;
				
				ALPHA = mix(opacity_edge, opacity_center, is_center) * final_fade;
			}
		}
	}
}