// Copyright (c) 2023-2025 Cory Petkovsek and Contributors // Copyright (c) 2021 J. Cuellar // This shader is based on DanilS clouds shader with MIT License // See https://github.com/danilw/godot-utils-and-other/tree/master/Dynamic%20sky%20and%20reflection shader_type spatial; render_mode unshaded, blend_mix, depth_draw_never, cull_front, skip_vertex_transform; uniform vec3 _sun_direction; uniform vec3 _moon_direction; uniform float _clouds_coverage; uniform float _clouds_thickness; uniform float _clouds_absorption; uniform float _clouds_noise_freq; uniform float _clouds_sky_tint_fade; uniform float _clouds_intensity; uniform float _clouds_size; uniform float _clouds_speed; uniform vec3 _clouds_direction; uniform sampler2D _clouds_texture; uniform vec4 _clouds_day_color: source_color; uniform vec4 _clouds_horizon_light_color: source_color; uniform vec4 _clouds_night_color: source_color; const int kCLOUDS_STEP = 10; uniform vec3 _clouds_partial_mie_phase; uniform float _clouds_mie_intensity; uniform vec4 _atm_sun_mie_tint; uniform vec4 _atm_moon_mie_tint: source_color; const float kPI = 3.1415927f; const float kINV_PI = 0.3183098f; const float kHALF_PI = 1.5707963f; const float kINV_HALF_PI = 0.6366198f; const float kQRT_PI = 0.7853982f; const float kINV_QRT_PI = 1.2732395f; const float kPI4 = 12.5663706f; const float kINV_PI4 = 0.0795775f; const float k3PI16 = 0.1193662f; const float kTAU = 6.2831853f; const float kINV_TAU = 0.1591549f; const float kE = 2.7182818f; float saturate(float value){ return clamp(value, 0.0, 1.0); } vec3 saturateRGB(vec3 value){ return clamp(value.rgb, 0.0, 1.0); } float pow3(float real){ return real * real * real; } float noiseClouds(vec3 p){ vec3 pos = vec3(p * 0.01); pos.z *= 256.0; vec2 offset = vec2(0.317, 0.123); vec4 uv= vec4(0.0); uv.xy = pos.xy + offset * floor(pos.z); uv.zw = uv.xy + offset; float x1 = textureLod(_clouds_texture, uv.xy, 0.0).r; float x2 = textureLod(_clouds_texture, uv.zw, 0.0).r; return mix(x1, x2, fract(pos.z)); } float cloudsFBM(vec3 p, float l){ float ret; ret = 0.51749673 * noiseClouds(p); p *= l; ret += 0.25584929 * noiseClouds(p); p *= l; ret += 0.12527603 * noiseClouds(p); p *= l; ret += 0.06255931 * noiseClouds(p); return ret; } float noiseCloudsFBM(vec3 p, float freq){ return cloudsFBM(p, freq); } float remap(float value, float fromMin, float fromMax, float toMin, float toMax){ return toMin + (value - fromMin) * (toMax - toMin) / (fromMax - fromMin); } float cloudsDensity(vec3 p, vec3 offset, float t){ vec3 pos = p * 0.0212242 - offset; float dens = noiseCloudsFBM(pos, _clouds_noise_freq); dens += dens; float cov = 1.0-_clouds_coverage; cov = smoothstep(0.00, (cov * 3.5) + t, dens); dens *= cov; dens = remap(dens, 1.0-cov, 1.0, 0.0, 1.0); return saturate(dens); } bool IntersectSphere(float r, vec3 origin, vec3 dir, out float t, out vec3 nrm) { origin += vec3(0.0, 450.0, 0.0); float a = dot(dir, dir); float b = 2.0 * dot(origin, dir); float c = dot(origin, origin) - r * r; float d = b * b - 4.0 * a * c; if(d < 0.0) return false; d = sqrt(d); a *= 2.0; float t1 = 0.5 * (-b + d); float t2 = 0.5 * (-b - d); if(t1<0.0) t1 = t2; if(t2 < 0.0) t2 = t1; t1 = min(t1, t2); if(t1 < 0.0) return false; nrm = origin + t1 * dir; t = t1; return true; } float miePhase(float mu, vec3 partial){ return kPI4 * (partial.x) * (pow(partial.y - partial.z * mu, -1.5)); } vec4 renderClouds2(vec3 ro, vec3 rd, float tm, float am){ vec4 ret = vec4(0, 0, 0, 0); vec3 wind = _clouds_direction * (tm * _clouds_speed); float a = 0.0; // n and tt doesnt need to be initialized since it would be set by IntersectSphere vec3 n; float tt; if(IntersectSphere(500, ro, rd, tt, n)) { float marchStep = float(kCLOUDS_STEP) * _clouds_thickness; vec3 dirStep = rd / rd.y * marchStep; vec3 pos = n * _clouds_size; vec2 mu = vec2(dot(_sun_direction, rd), dot(_moon_direction, rd)); vec3 mph = ((miePhase(mu.x, _clouds_partial_mie_phase) * _atm_sun_mie_tint.rgb) + miePhase(mu.y, _clouds_partial_mie_phase) * am); vec4 t = vec4(1.0); t.rgb += (mph.rgb * _clouds_mie_intensity); for(int i = 0; i < kCLOUDS_STEP; i++) { float h = float(i) * 0.1; // / float(kCLOUDS_STEP); float density = cloudsDensity(pos, wind, h); float sh = saturate(exp(-_clouds_absorption * density * marchStep)); t *= sh; ret += (t * (exp(h) * 0.571428571) * density * marchStep); a += (1.0 - sh) * (1.0 - a); pos += dirStep; } return vec4(ret.rgb * _clouds_intensity, a); } return vec4(ret.rgb * _clouds_intensity, a); } varying vec4 world_pos; varying vec4 moon_coords; varying vec3 deep_space_coords; varying vec4 angle_mult; void vertex(){ vec4 vert = vec4(VERTEX, 0.0); POSITION = PROJECTION_MATRIX * MODELVIEW_MATRIX * vert; POSITION.z = 0.0000001; world_pos = (MODEL_MATRIX * vert); angle_mult.x = saturate(1.0 - _sun_direction.y); angle_mult.y = saturate(_sun_direction.y + 0.45); angle_mult.z = saturate(-_sun_direction.y + 0.30); angle_mult.w = saturate(-_sun_direction.y + 0.60); } void fragment(){ vec3 ray = normalize(world_pos).xyz; float horizonBlend = saturate((ray.y+0.01) * 50.0); vec4 clouds = renderClouds2(vec3(0.0, 0.0, 0.0), ray, TIME, angle_mult.z); clouds.a = saturate(clouds.a); clouds.rgb *= mix(mix(_clouds_day_color.rgb, _clouds_horizon_light_color.rgb, angle_mult.x), _clouds_night_color.rgb, angle_mult.w); clouds.a = mix(0.0, clouds.a, horizonBlend); ALBEDO = clouds.rgb; ALPHA = pow3(clouds.a); }