#version 330 uniform vec2 resolution; uniform vec3 camera_forward; uniform vec3 camera_right; uniform vec3 camera_up; uniform vec3 sun_direction; uniform float aspect_ratio; uniform float tan_half_fovy; out vec4 finalColor; void main() { /* * Reconstruct a world-space direction for this screen pixel. */ vec2 screen = gl_FragCoord.xy / resolution; vec2 ndc = screen * 2.0 - 1.0; vec3 view_direction = normalize( camera_forward + camera_right * ndc.x * aspect_ratio * tan_half_fovy + camera_up * ndc.y * tan_half_fovy ); vec3 moon_direction = -sun_direction; /* * Vertical sky gradient. */ float height = smoothstep( -0.20, 0.80, view_direction.y ); /* * Day/night transition based on the sun's elevation. */ float day_amount = smoothstep( -0.10, 0.12, sun_direction.y ); float night_amount = 1.0 - day_amount; vec3 night_horizon = vec3( 0.055, 0.045, 0.110 ); vec3 night_zenith = vec3( 0.005, 0.008, 0.025 ); vec3 day_horizon = vec3( 0.620, 0.780, 0.920 ); vec3 day_zenith = vec3( 0.080, 0.280, 0.620 ); vec3 night_sky = mix( night_horizon, night_zenith, height ); vec3 day_sky = mix( day_horizon, day_zenith, height ); vec3 sky = mix( night_sky, day_sky, day_amount ); /* * Sunrise and sunset colouring. */ float horizon = 1.0 - smoothstep( 0.0, 0.35, abs(view_direction.y) ); float twilight = 1.0 - smoothstep( 0.02, 0.28, abs(sun_direction.y) ); float sun_alignment = dot( view_direction, sun_direction ); float sun_facing = max( sun_alignment, 0.0 ); /* * Avoid pow(): x^4 is sufficient for the broad sunset effect. */ float sun_facing_2 = sun_facing * sun_facing; float sun_facing_4 = sun_facing_2 * sun_facing_2; vec3 sunset_colour = vec3( 0.65, 0.16, 0.035 ); sky += sunset_colour * horizon * twilight * sun_facing_4; /* * Sun halo. * * The values are precalculated cosine values. Since both * view_direction and sun_direction are normalized, their dot * product is the cosine of the angle between them. * * Wide halo: * outer edge: 18 degrees * inner edge: 3 degrees * * Core halo: * outer edge: 7 degrees * inner edge: 1 degree */ float sun_wide = smoothstep( 0.9510565, 0.9986295, sun_alignment ); float sun_core = smoothstep( 0.9925462, 0.9998477, sun_alignment ); /* * Moon halo. * * Because the moon is directly opposite the sun in this model, * its alignment is the negative sun alignment. * * Wide halo: * outer edge: 14 degrees * inner edge: 2 degrees * * Core halo: * outer edge: 5 degrees * inner edge: 0.5 degrees */ float moon_alignment = -sun_alignment; float moon_wide = smoothstep( 0.9702957, 0.9993908, moon_alignment ); float moon_core = smoothstep( 0.9961947, 0.9999619, moon_alignment ); /* * Fade each halo near and below the horizon. * * These ranges are deliberately broader than the symbol fade so * the surrounding light disappears gradually. */ float sun_above_horizon = smoothstep( -0.12, 0.04, sun_direction.y ); float moon_above_horizon = smoothstep( -0.10, 0.04, moon_direction.y ); /* * Warm the sun halo around sunrise and sunset. */ vec3 daylight_glow = vec3( 1.00, 0.82, 0.38 ); vec3 sunset_glow = vec3( 1.00, 0.25, 0.035 ); vec3 sun_glow_colour = mix( daylight_glow, sunset_glow, twilight ); vec3 moon_glow_colour = vec3( 0.32, 0.46, 0.82 ); /* * Broad component blends the sprite into the sky. * Core component makes the centre appear luminous. */ float sun_glow = ( sun_wide * 0.13 + sun_core * 0.32 ) * sun_above_horizon; float moon_glow = ( moon_wide * 0.08 + moon_core * 0.17 ) * moon_above_horizon * night_amount; /* * Soft screen-like blending. This brightens the sky without * immediately clipping bright daytime colours to white. */ sky += (1.0 - sky) * sun_glow_colour * sun_glow; sky += (1.0 - sky) * moon_glow_colour * moon_glow; finalColor = vec4( clamp(sky, 0.0, 1.0), 1.0 ); }