@group(0) @binding(0) var<uniform> viewProjectionMatrix : mat4x4<f32>;
@group(0) @binding(1) var<uniform> cameraPosition : vec3<f32>;

struct VertexOutput {
	@builtin(position) position    : vec4<f32>,
	@location(0) worldPosition     : vec3<f32>,
	@location(1) worldNormal       : vec3<f32>,
};

@vertex
fn v_main(
	@location(0) position : vec3<f32>,
	@location(1) normal   : vec3<f32>
) -> VertexOutput {

	var output : VertexOutput;

	output.position      = viewProjectionMatrix * vec4<f32>( position, 1.0 );
	output.worldPosition = position;
	output.worldNormal   = normalize( normal );

	return output;

}

struct FragmentOutput {
	@location(0) color : vec4<f32>,
	@builtin(frag_depth) depth : f32,
};

@fragment
fn f_main( input : VertexOutput ) -> FragmentOutput {

	let surfaceDir : vec3<f32> = normalize( input.worldPosition );

	let up : vec3<f32> = vec3<f32>( 0.0, 1.0, 0.0 );

	let cosAngle : f32 = clamp( dot( surfaceDir, up ), 0.0, 1.0 );

	let skyZenith : vec3<f32> = vec3<f32>( 0.45, 0.78, 0.98 );

	let skyHorizon : vec3<f32> = vec3<f32>( 0.12, 0.28, 0.52 );

	let sunDir : vec3<f32> = normalize( vec3<f32>( -0.1, 0.97, 0.2 ) );

	let sunAngle : f32 = clamp( dot( surfaceDir, sunDir ), 0.0, 1.0 );

	let sunExposure : f32 = smoothstep( 0.94, 0.999, sunAngle );

	let skyGradient : vec3<f32> = mix( skyHorizon, skyZenith, pow( cosAngle, 1.1 ) );

	let airglow : vec3<f32> = vec3<f32>( 0.09, 0.16, 0.28 ) * pow( 1.0 - cosAngle, 3.0 );

	let scattering : vec3<f32> = skyGradient + airglow;

	let sunDisk : vec3<f32> = vec3<f32>( 1.0, 0.94, 0.76 ) * sunExposure * sunExposure * 1.6;

	let skyColor : vec3<f32> = mix( scattering, scattering + sunDisk, sunExposure );

	let horizonBlend : f32 = smoothstep( 0.0, 0.6, 1.0 - cosAngle );

	let baseColor : vec3<f32> = mix( skyHorizon, skyZenith, max( cosAngle, 0.1 ) );

	let color : vec3<f32> = mix( baseColor * 1.1 + vec3<f32>( 0.02, 0.03, 0.04 ), skyColor * 0.9, 1.0 - horizonBlend );

	return FragmentOutput(

		vec4<f32>( color, 1.0 ),

		0.999

	);

}
