diff --git a/project.godot b/project.godot index fc124ec..68003ad 100644 --- a/project.godot +++ b/project.godot @@ -26,3 +26,22 @@ Wait="*res://autoload/Wait/Wait.gd" theme/custom="res://ui/Theme.tres" theme/custom_font="res://ui/Blockies.otf" + +[shader_globals] + +wet={ +"type": "float", +"value": 0.0 +} +night={ +"type": "float", +"value": 0.0 +} +wind={ +"type": "float", +"value": 0.25 +} +overcast={ +"type": "float", +"value": 0.25 +} diff --git a/shaders/sky.gdshader b/shaders/sky.gdshader new file mode 100644 index 0000000..1702924 --- /dev/null +++ b/shaders/sky.gdshader @@ -0,0 +1,111 @@ +shader_type sky; +/// Procedural sky supporting overcast and time of day. + +/// Color of the sky in the daytime. +const vec3 COLOR_DAY = vec3(0.0, 0.41, 0.8); +/// Color of the horizon at sunrise and sunset. +const vec3 COLOR_TWILIGHT = vec3(1.0, 0.29, 0.0); +/// Color of the sky at night. +const vec3 COLOR_NIGHT = vec3(0.01, 0.0, 0.03); +/// Typical color of the clouds. +const vec3 COLOR_CLOUDS_LIGHT = vec3(2.0); +/// Shade the clouds take on at peak overcast. +const vec3 COLOR_CLOUDS_HEAVY = vec3(0.25); +/// Multipliers for the clouds' color at night. +const vec3 MUL_CLOUDS_NIGHT = vec3(0.0); +/// Multiplier for the clouds' color at their edges. +const vec3 MUL_CLOUDS_EDGE = vec3(0.75); +/// Threshold between 0-to-mask and mask-to-1 interpolation of cloud alpha. +const float ALPHA_THRESHOLD_CLOUDS = 0.25; +/// Color of the stars. +const vec3 COLOR_STARS = vec3(2.0); +/// Radiance color of the sky in the daytime. +const vec3 RADIANCE_DAY = vec3(0.625); +/// Radiance color of the sky at sunrise and sunset. +const vec3 RADIANCE_TWILIGHT = COLOR_TWILIGHT/2.0; +/// Radiance color of the sky at night. +const vec3 RADIANCE_NIGHT = 3.0*COLOR_NIGHT; +/// Multipliers for the radiance color of the sky at peak overcast. +const vec3 MUL_RADIANCE_OVERCAST = vec3(0.875); +/// Peak wind velocity in UV units per second. +const vec2 PEAK_WIND = vec2(0.25, 0.0); + +/// Alpha mask for the cloud layer. +uniform sampler2D cloud_map: + source_color, filter_linear, repeat_enable, hint_default_black; +/// Alpha mask for the star layer. +uniform sampler2D star_map: + source_color, filter_linear, repeat_enable, hint_default_black; +/// Interpolates between brightest time of day and darkest time of night. +global uniform float night = 0.0; +/// Interpolates quadratically between clear sky and cloudy sky. +global uniform float overcast = 0.25; +/// Interpolates quadratically between no wind and maximum wind. +global uniform float wind = 0.25; + +/// Computes cloud RGBA at given UV. +vec4 clouds(vec2 uv) { + float sq = overcast*overcast; + float m = texture(cloud_map, uv).r; + float s = step(ALPHA_THRESHOLD_CLOUDS, sq); + return vec4( + mix(COLOR_CLOUDS_LIGHT, COLOR_CLOUDS_HEAVY, sq) * + mix(MUL_CLOUDS_EDGE, vec3(1.0), m) * + mix(vec3(1.0), MUL_CLOUDS_NIGHT, night), + mix( + mix(0.0, m, smoothstep(0.0, ALPHA_THRESHOLD_CLOUDS, sq)), + mix(m, 1.0, smoothstep(ALPHA_THRESHOLD_CLOUDS, 1.0, sq)), + s + ) + ); +} + +/// Computes star RGBA at given UV. +vec4 stars(vec2 uv) { + float m = texture(star_map, uv).r; + return vec4(COLOR_STARS, mix(mix(0.0, m, night), 0.0, sqrt(overcast))); +} + +/// Computes atmospheric scattering RGB at given UV. +vec3 background(vec2 uv) { + vec3 top = mix(COLOR_DAY, COLOR_NIGHT, night); + vec3 bottom = mix( + top, COLOR_TWILIGHT, + smoothstep(0.5, 0.0, abs(0.5 - night)) + ); + return mix( + mix(top, bottom, uv.y), + COLOR_CLOUDS_HEAVY * MUL_CLOUDS_EDGE * + mix(vec3(1.0), MUL_CLOUDS_NIGHT, night), + overcast + ); +} + +/// Computes solid radiance color for entire sky. +vec3 radiance() { + return mix( + mix(RADIANCE_DAY, RADIANCE_NIGHT, night), + RADIANCE_TWILIGHT, + smoothstep(1.0, 0.0, abs(0.5 - night)) + )*mix(vec3(1.0), MUL_RADIANCE_OVERCAST, overcast); +} + +/// Alpha-blends overlay over opaque underlay. +vec3 alpha_blend_opaque(vec4 overlay, vec3 underlay) { + return mix(underlay, overlay.rgb, overlay.a); +} + +/// Composites clouds over stars over background, plus wind and edge fading. +vec3 composite(vec2 uv) { + vec2 uv_after_wind = fract(uv + TIME*wind*wind*PEAK_WIND); + vec3 color = background(uv); + vec4 fade = sqrt(vec4(vec3(1.0), smoothstep(0.5, 0.0, abs(0.5 - uv.y)))); + color = alpha_blend_opaque(stars(uv)*fade, color); + color = alpha_blend_opaque(clouds(uv_after_wind)*fade, color); + return color; +} + +/// Shader sky pass. +void sky() { + COLOR = AT_CUBEMAP_PASS? radiance() : composite(SKY_COORDS); +} \ No newline at end of file