Extension of Sky++ (sorta) by Ansol

Extension of Sky++ (sorta) by Ansol (CC0), built for our game BROODSAC. Keeps the original atmospheric scattering (Rayleigh/Mie/ozone) and volumetric cumulus clouds, and adds:

  • A flat cirrus layer (textured, with distortion and mask) above the cumulus
  • Fully procedural stars, no texture, three noise layers with hashed presence/size/brightness/color, fading with sun elevation
  • Night grading pass (blends toward a desaturated blue tint at low light levels, rough scotopic vision approximation)
  • Sun/moon discs tinted by atmospheric transmittance
  • Optional double rainbow
  • Debanding pass

 

Full credit to Ansol for the base shader. This is a public fork/extension, feel free to use or extend further.

Shader code
shader_type sky;
render_mode use_quarter_res_pass, use_half_res_pass;

#define H(p)  fract(sin(mod(dot(p, vec2(12.9898, 78.233)),6.283)) * 43758.5453)

const float EPS = 1e-6;
const float INFINITY = 1.0 / 0.0;
const float PLANET_RADIUS = 6371000.0;
const vec3 PLANET_CENTER = vec3(0.0, -PLANET_RADIUS, 0.0);
const float ATMOSPHERE_HEIGHT = 100000.0;
const float RAYLEIGH_HEIGHT = (ATMOSPHERE_HEIGHT * 0.08);
const float MIE_HEIGHT = (ATMOSPHERE_HEIGHT * 0.012);

uniform bool use_debanding = true;
uniform bool enable_shader = true;

group_uniforms Atmosphere;
uniform int atmosphere_sample_count = 64;
uniform float elevation = 0.0;
uniform float rayleigh_strength : hint_range(0.0, 5.0) = 1.0;
uniform float mie_strength      : hint_range(0.0, 5.0) = 1.0;
uniform float ozone_strength    : hint_range(0.0, 5.0) = 1.0;

const vec3 C_RAYLEIGH = vec3(5.802, 13.558, 33.100) * 1e-6;
const vec3 C_MIE      = vec3(3.996,  3.996,  3.996) * 1e-6;
const vec3 C_OZONE    = vec3(0.650,  1.881,  0.085) * 1e-6;

uniform float mie_anisotropy_factor = 0.75;
uniform float atmosphere_density : hint_range(0.0, 5.0) = 1.0;
uniform float exposure = 10.0;
uniform float sun_disc_feather : hint_range(0.0, 1.0) = 0.5;
uniform float sundisc_intensity = 100.0;

group_uniforms Moon;
uniform float moon_disc_intensity : hint_range(0.0, 50.0) = 4.0;
uniform float moon_disc_feather : hint_range(0.0, 1.0) = 0.35;

group_uniforms NightRealism;
uniform float scotopic_start_energy : hint_range(0.0, 2.0) = 0.35;
uniform float scotopic_full_energy : hint_range(0.0, 2.0) = 0.02;
uniform float night_desaturation : hint_range(0.0, 1.0) = 0.85;
uniform vec3 scotopic_tint : source_color = vec3(0.6, 0.75, 0.95);

group_uniforms Stars;
uniform float stars_density    : hint_range(0.0, 1.0) = 0.5;
uniform float stars_brightness : hint_range(0.0, 10.0) = 3.0;
uniform float stars_size       : hint_range(0.0001, 0.008) = 0.0015;
uniform bool  stars_colored    = true;
uniform bool  dim_stars_at_day = true;
uniform mat3  stars_rotation   = mat3(1.0);
uniform float moon_cull_margin : hint_range(1.0, 6.0) = 3.0;

#define LOWER_PLANE_HEIGHT 3.0

group_uniforms CumulusClouds;
uniform bool  hole_in_center = false;
uniform float hole_radius = 5.0;
uniform float hole_feather = 10.0;
uniform float cloud_falloff_coeff : hint_range(0.0, 1.0) = 0.3;
uniform float clouds_alpha_lower_bound = 0.0;
uniform float clouds_alpha_upper_bound = 0.15;
uniform sampler2D cloud_color_texture : hint_default_white;
uniform vec3  cloud_base_color    : source_color = vec3(.85, .85, .9);
uniform vec3  cloud_overcast_color : source_color = vec3(.35, .4, .45);
uniform float coverage : hint_range(0.0, 1.0) = 0.35;
uniform float cloud_smoothness : hint_range(0.0, 0.2) = 0.05;

group_uniforms CumulusClouds.RayMarchParameters;
uniform bool  apply_stochastic_jitter = false;
uniform float stochastic_jitter_amount : hint_range(0.0, 1.0) = 0.1;
uniform float cloud_base_march_dist = 10.0;
uniform int   cloud_marches : hint_range(4, 64, 1) = 64;
uniform float density_coeff : hint_range(0.0, 2.0) = 1.0;
uniform float cloud_transmittance_cutoff : hint_range(0.0, 0.1) = 0.01;

group_uniforms CumulusClouds.Wind;
uniform vec2  wind_direction = vec2(1.0, 0.3);
uniform float wind_speed : hint_range(0.0, 50.0) = 2.0;
uniform float wind_loop_period = 2000.0;
uniform vec2  noise_wind_direction = vec2(0.3, 1.0);
uniform float noise_wind_speed_mult : hint_range(0.0, 10.0) = 2.0;

group_uniforms CumulusClouds.Textures;
uniform float     cloud_noise_factor : hint_range(0.0, 1.0) = 0.5;
uniform sampler3D cloud_shape : filter_linear_mipmap, repeat_enable;
uniform float     cloud_shape_size = 1.0;
uniform vec3      cloud_shape_offset = vec3(0.0);
uniform sampler3D cloud_noise : filter_linear_mipmap, repeat_enable;
uniform float     cloud_noise_size = 1.0;
uniform vec3      cloud_noise_offset = vec3(0.0);

group_uniforms CumulusClouds.LightPass;
uniform float clouds_anisotropy_factor : hint_range(0.0, 1.0) = 0.25;
uniform int   light_marches : hint_range(4, 32, 1) = 8;
uniform float light_max_dist = 5.0;
uniform float light_strength = 15.0;
uniform float ambient_light_multiplier : hint_range(0.0, 5.0) = 1.0;

group_uniforms CirrusClouds;
uniform bool      use_cirrus = true;
uniform sampler2D cirrus_texture : hint_default_black;
uniform vec2      cirrus_squish = vec2(4.0, 1.0);
uniform float     cirrus_scale = 1.0;
uniform float     cirrus_treshold : hint_range(0.0, 1.0) = .75;
uniform float     cirrus_feather  : hint_range(0.0, 1.0) = .25;
uniform vec2      cirrus_offset = vec2(0.0);
uniform sampler2D cirrus_distortion_texture : hint_default_black;
uniform float     cirrus_distortion_scale = 1.0;
uniform float     cirrus_distortion_strength = .4;
uniform vec2      cirrus_distortion_offset = vec2(0.0);
uniform sampler2D cirrus_mask_texture : hint_default_white;
uniform float     cirrus_mask_scale = 1.0;
uniform float     cirrus_mask_treshold : hint_range(0.0, 1.0) = .6;
uniform float     cirrus_mask_feather  : hint_range(0.0, 1.0) = .4;
uniform float     cirrus_opacity : hint_range(0.0, 1.0) = 0.2;

group_uniforms Rainbow;
uniform bool      use_rainbow = false;
uniform bool      behind_clouds = false;
uniform sampler2D rainbow_gradient : hint_default_white, filter_linear;
uniform float     rainbow_width = .05;
uniform float     rainbow_offset = .65;
uniform float     rainbow_opacity : hint_range(0.0, 1.0) = .1;
uniform bool      double_rainbow = true;

#define saturate(a) clamp(a, 0.0, 1.0)

vec2 sphere_intersection(vec3 rayStart, vec3 rayDir, vec3 sphereCenter, float sphereRadius) {
	rayStart -= sphereCenter;
	float a = dot(rayDir, rayDir);
	float b = 2.0 * dot(rayStart, rayDir);
	float c = dot(rayStart, rayStart) - (sphereRadius * sphereRadius);
	float d = b * b - 4.0 * a * c;
	if (d < 0.0) return vec2(-1.0);
	d = sqrt(d);
	return vec2(-b - d, -b + d) / (2.0 * a);
}
vec2 planet_intersection(vec3 rayStart, vec3 rayDir) {
	return sphere_intersection(rayStart, rayDir, PLANET_CENTER, PLANET_RADIUS);
}
vec2 atmosphere_intersection(vec3 rayStart, vec3 rayDir) {
	return sphere_intersection(rayStart, rayDir, PLANET_CENTER, PLANET_RADIUS + ATMOSPHERE_HEIGHT);
}
float phase_rayleigh(float costh) {
	return 3.0 * (1.0 + costh * costh) / (16.0 * PI);
}
float phase_mie(float costh) {
	float g = min(mie_anisotropy_factor, 0.9381);
	float k = 1.55 * g - 0.55 * g * g * g;
	float kcosth = k * costh;
	return (1.0 - k * k) / ((4.0 * PI) * (1.0 - kcosth) * (1.0 - kcosth));
}
float atmosphere_height(vec3 position_world_space) {
	return distance(position_world_space, PLANET_CENTER) - PLANET_RADIUS;
}
float density_rayleigh(float h) { return exp(-max(0.0, h / RAYLEIGH_HEIGHT)); }
float density_mie(float h)      { return exp(-max(0.0, h / MIE_HEIGHT)); }
float density_ozone(float h)    { return max(0.0, 1.0 - abs(h - 25000.0) / 15000.0); }
vec3  density_atmosphere(float h) {
	return vec3(density_rayleigh(h), density_mie(h), density_ozone(h));
}
vec3 integrate_optical_depth(vec3 rayStart, vec3 rayDir) {
	vec2  intersection = atmosphere_intersection(rayStart, rayDir);
	float rayLength    = intersection.y;
	int   sampleCount  = 8;
	float stepSize     = rayLength / float(sampleCount);
	vec3  opticalDepth = vec3(0.0);
	for (int i = 0; i < sampleCount; i++) {
		vec3  localPosition = rayStart + rayDir * (float(i) + 0.5) * stepSize;
		float localHeight   = atmosphere_height(localPosition);
		opticalDepth += density_atmosphere(localHeight) * stepSize;
	}
	return opticalDepth;
}
vec3 absorb(vec3 opticalDepth) {
	return exp(-(
		opticalDepth.x * C_RAYLEIGH * rayleigh_strength +
		opticalDepth.y * C_MIE     * mie_strength +
		opticalDepth.z * C_OZONE   * ozone_strength
	) * atmosphere_density);
}
vec3 integrate_scattering(vec3 rayStart, vec3 rayDir, float rayLength,
		vec3 lightDir, vec3 lightColor, out vec3 transmittance) {
	float rayHeight = atmosphere_height(rayStart);
	float sampleDistributionExponent = 1.0 + saturate(1.0 - rayHeight / ATMOSPHERE_HEIGHT) * 8.0;
	vec2  intersection = atmosphere_intersection(rayStart, rayDir);
	rayLength = min(rayLength, intersection.y);
	if (intersection.x > 0.0) {
		rayStart  += rayDir * intersection.x;
		rayLength -= intersection.x;
	}
	float costh  = dot(rayDir, lightDir);
	float phaseR = phase_rayleigh(costh);
	float phaseM = phase_mie(costh);
	vec3  opticalDepth = vec3(0.0);
	vec3  rayleigh     = vec3(0.0);
	vec3  mie          = vec3(0.0);
	float prevRayTime  = 0.0;
	for (int i = 0; i < atmosphere_sample_count; i++) {
		float rayTime  = pow(float(i) / float(atmosphere_sample_count), sampleDistributionExponent) * rayLength;
		float stepSize = (rayTime - prevRayTime);
		vec3  localPosition = rayStart + rayDir * rayTime;
		float localHeight   = atmosphere_height(localPosition);
		vec3  localDensity  = density_atmosphere(localHeight);
		opticalDepth += localDensity * stepSize;
		vec3 viewTransmittance  = absorb(opticalDepth);
		vec3 opticalDepthlight  = integrate_optical_depth(localPosition, lightDir);
		vec3 lightTransmittance = absorb(opticalDepthlight);
		rayleigh += viewTransmittance * lightTransmittance * phaseR * localDensity.x * stepSize;
		mie      += viewTransmittance * lightTransmittance * phaseM * localDensity.y * stepSize;
		prevRayTime = rayTime;
	}
	transmittance = absorb(opticalDepth);
	return (rayleigh * C_RAYLEIGH * rayleigh_strength + mie * C_MIE * mie_strength) * lightColor * exposure;
}
float celestial_disc(vec3 eyedir, vec3 dir, float theta_r, float feather) {
	float cos_angle = dot(eyedir, dir);
	float cos_inner = cos(theta_r * (1.0 - feather));
	float cos_outer = cos(theta_r * (1.0 + feather));
	return smoothstep(cos_outer, cos_inner, cos_angle);
}
float rand(vec2 co) {
	return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
}

vec3 apply_scotopic_grading(vec3 col, float total_light_energy) {
	float night_factor = 1.0 - smoothstep(scotopic_full_energy, scotopic_start_energy, total_light_energy);
	float lum = dot(col, vec3(0.299, 0.587, 0.114));
	vec3  night_col = lum * scotopic_tint;
	return mix(col, night_col, night_desaturation * night_factor);
}

float take_cloud_sample(vec3 coord) {
	vec3 shape_wind_offset = vec3(normalize(wind_direction), 0.0).xzy
		* mod(TIME * wind_speed, wind_loop_period);
	vec3 noise_wind_offset = vec3(normalize(noise_wind_direction), 0.0).xzy
		* mod(TIME * wind_speed * noise_wind_speed_mult, wind_loop_period);

	float shape_sample = texture(cloud_shape, ((coord + shape_wind_offset) * cloud_shape_size * 0.01) + cloud_shape_offset).r;
	float noise_sample = texture(cloud_noise, ((coord + noise_wind_offset) * cloud_noise_size * 0.01) + cloud_noise_offset).r;
	float mixed_sample = shape_sample * (1.0 - cloud_noise_factor) + noise_sample * cloud_noise_factor;
	if (hole_in_center) {
		float hole_factor = smoothstep(hole_radius - hole_feather, hole_radius + hole_feather, length(coord.xz));
		mixed_sample *= hole_factor;
	}
	float invert_coverage = 1.0 - coverage;
	return smoothstep(invert_coverage - cloud_smoothness, invert_coverage + cloud_smoothness, mixed_sample);
}
float henyey_greenstein(float a, float g) {
	float g2 = g * g;
	return (1.0 - g2) / (4.0 * PI * pow(1.0 + g2 - 2.0 * g * a, 1.5));
}
float light_march(vec3 ray_origin, vec3 ray_direction, vec3 sun_direction) {
	float optical_depth = 0.0;
	float step_size     = light_max_dist / float(light_marches);
	for (float total_dist = 0.0; total_dist < light_max_dist; total_dist += step_size) {
		vec3  coords         = ray_origin + sun_direction * total_dist;
		float density_sample = take_cloud_sample(coords);
		optical_depth += density_sample * step_size;
	}
	return exp(-optical_depth);
}
vec4 ray_march_clouds(vec3 start_point, vec3 direction, vec3 ambient_color, vec2 uv,
		vec3 light_dir, vec3 light_color, float light_energy, float total_light_energy) {
	vec3  scattered_light = vec3(0.0);
	float transmittance = 1.0;
	float march_dist    = cloud_base_march_dist
		/ clamp(pow(dot(direction, vec3(0.0, 1.0, 0.0)), cloud_falloff_coeff), 0.05, 1.0);
	float step_size  = (march_dist / float(cloud_marches)) - EPS;
	float cos_theta  = dot(direction, light_dir);
	float phase_cloud = henyey_greenstein(cos_theta, clouds_anisotropy_factor);
	if (apply_stochastic_jitter)
		start_point += direction * (H(uv) - 0.5) * stochastic_jitter_amount;
	vec3 cloud_color = vec3(0.0);
	int  color_samples = 0;
	for (float total_dist = 0.0; total_dist < march_dist; total_dist += step_size) {
		if (transmittance < cloud_transmittance_cutoff) break;

		vec3  coords         = start_point + direction * total_dist;
		float density_sample = take_cloud_sample(coords);
		cloud_color += mix(
			cloud_base_color,
			cloud_overcast_color,
			smoothstep(.4, .8, texture(cloud_color_texture, coords.xz * .01).r)
		);
		color_samples++;
		if (density_sample > 0.01) {
			transmittance *= exp(-density_sample * density_coeff * step_size);
			float luminance = light_march(coords, direction, light_dir);
			scattered_light += density_sample * transmittance * density_coeff
				* step_size * luminance * phase_cloud * light_strength;
		}
	}
	cloud_color /= float(max(color_samples, 1));

	vec3  ambient_term = ambient_color * ambient_light_multiplier;
	vec3  direct_term  = scattered_light * light_color * light_energy;
	vec3  cloud_col    = cloud_color * (ambient_term + direct_term);

	cloud_col = apply_scotopic_grading(cloud_col, total_light_energy);

	transmittance = clamp(1.0 - transmittance, 0.0, 1.0);
	return vec4(cloud_col, transmittance);
}
vec3 jitter_ray_origin(vec3 origin, vec3 direction, vec2 noise_sample, float amount) {
	vec3 up       = abs(direction.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
	vec3 tangent  = normalize(cross(up, direction));
	vec3 bitangent = normalize(cross(direction, tangent));
	vec2 offset2D = (noise_sample - 0.5) * amount;
	return origin + tangent * offset2D.x + bitangent * offset2D.y;
}
vec3 rainbow(vec3 eyedir, vec3 transmittance, vec4 clouds) {
	vec3 res = vec3(0.0);
	{
		float lower_bound = rainbow_offset - rainbow_width;
		float upper_bound = rainbow_offset + rainbow_width;
		res += texture(rainbow_gradient, vec2(smoothstep(lower_bound, upper_bound, eyedir.x), 0.0)).rgb
			* smoothstep(lower_bound, lower_bound + .02, eyedir.x)
			* smoothstep(upper_bound, upper_bound - .02, eyedir.x)
			* rainbow_opacity * transmittance
			* (behind_clouds ? (1.0 - clouds.a) : 1.0);
	}
	if (double_rainbow) {
		float lower_bound = rainbow_offset * 0.9 - rainbow_width * 1.5;
		float upper_bound = rainbow_offset * 0.9 + rainbow_width * 1.5;
		res += texture(rainbow_gradient, vec2(smoothstep(lower_bound, upper_bound, eyedir.x), 0.0)).rgb
			* smoothstep(lower_bound, lower_bound + .02, eyedir.x)
			* smoothstep(upper_bound, upper_bound - .02, eyedir.x)
			* rainbow_opacity * .15 * transmittance
			* (behind_clouds ? (1.0 - clouds.a) : 1.0);
	}
	return res;
}

float _h(vec3 p) {
	p  = fract(p * vec3(127.1, 311.7,  74.7));
	p += dot(p, p.zxy + 31.41);
	p  = fract(p * vec3(269.5, 183.3, 461.1));
	return fract(dot(p, vec3(1.0, 7.0, 3.0)));
}

vec3 _star_tint(float t) {
	return mix(
		vec3(1.0, 0.75, 0.5),
		mix(vec3(1.0, 0.98, 0.95), vec3(0.75, 0.88, 1.0), t),
		sqrt(t)
	);
}

vec3 _rot_x(vec3 v, float a) {
	float c = cos(a), s = sin(a);
	return vec3(v.x, c * v.y - s * v.z, s * v.y + c * v.z);
}
vec3 _rot_y(vec3 v, float a) {
	float c = cos(a), s = sin(a);
	return vec3(c * v.x + s * v.z, v.y, -s * v.x + c * v.z);
}
vec3 _rot_z(vec3 v, float a) {
	float c = cos(a), s = sin(a);
	return vec3(c * v.x - s * v.y, s * v.x + c * v.y, v.z);
}

vec3 _star_layer(vec3 dir, float scale, float thresh, float sz_mult, float br_mult) {
	vec3 nc = floor(dir * scale);

	float hd = _h(nc + vec3(71.3, 53.9, 97.1));
	if (hd > thresh) return vec3(0.0);

	float h1 = _h(nc + vec3( 3.7,  0.0,  0.0));
	float h2 = _h(nc + vec3( 0.0, 17.3,  0.0));
	float h3 = _h(nc + vec3( 0.0,  0.0, 31.7));
	float hb = _h(nc + vec3(43.1, 19.3,  7.5));
	float hc = _h(nc + vec3(59.3, 37.1, 23.9));

	vec3 star = normalize(nc + vec3(h1, h2, h3) - 0.5);

	float cos_a = dot(dir, star);
	if (cos_a < 0.9985) return vec3(0.0);

	float d2     = 1.0 - cos_a;
	float r      = stars_size * sz_mult * (hb * 0.6 + 0.4);
	float sigma2 = r * r * 0.5;

	vec3 col = stars_colored ? _star_tint(hc) : vec3(1.0);
	return col * (hb * hb) * br_mult * exp(-d2 / sigma2);
}

vec3 procedural_stars(vec3 dir) {
	vec3 d = normalize(stars_rotation * dir);

	vec3 c = _star_layer(d, 80.0, stars_density * 0.25, 2.2, 1.0);

	vec3 d2 = _rot_y(_rot_x(d, 0.65), 0.52);
	c += _star_layer(d2, 220.0, stars_density * 0.55, 1.0, 0.55);

	vec3 d3 = _rot_x(_rot_z(d, 1.04), 0.70);
	c += _star_layer(d3, 520.0, stars_density, 0.45, 0.2);

	return c * stars_brightness;
}

void sky() {
	if (!enable_shader) {
		if (AT_QUARTER_RES_PASS) {
			COLOR = vec3(1.0);
		} else if (AT_HALF_RES_PASS) {
			COLOR = vec3(0.0);
			ALPHA = 0.0;
		} else {
			COLOR = texture(RADIANCE, EYEDIR).rgb;
		}

	} else if (AT_CUBEMAP_PASS) {
		vec3 transmittance;
		COLOR = integrate_scattering(
			vec3(0.0, elevation, 0.0), EYEDIR, INFINITY,
			LIGHT0_DIRECTION, vec3(1.0, 0.996, 0.98), transmittance
		);

	} else if (AT_QUARTER_RES_PASS) {
		vec3 transmittance;
		integrate_scattering(
			vec3(0.0, elevation, 0.0), EYEDIR, INFINITY,
			LIGHT0_DIRECTION, vec3(1.0, 0.996, 0.98), transmittance
		);
		COLOR = transmittance;

	} else if (AT_HALF_RES_PASS) {
		COLOR = vec3(0.0);
		ALPHA = 0.0;
		if (EYEDIR.y > 0.0) {
			float sun_energy = LIGHT0_ENERGY * smoothstep(-0.02, 0.05, LIGHT0_DIRECTION.y);
			vec3  cloud_light_dir    = LIGHT0_DIRECTION;
			vec3  cloud_light_color  = LIGHT0_COLOR;
			float cloud_light_energy = sun_energy;
			float total_light_energy = sun_energy;

			if (LIGHT1_ENABLED) {
				float moon_energy = LIGHT1_ENERGY * smoothstep(-0.02, 0.05, LIGHT1_DIRECTION.y);
				total_light_energy = sun_energy + moon_energy;
				float moon_weight  = moon_energy / max(sun_energy + moon_energy, 1e-4);
				cloud_light_dir    = normalize(mix(LIGHT0_DIRECTION, LIGHT1_DIRECTION, moon_weight));
				cloud_light_color  = mix(LIGHT0_COLOR, LIGHT1_COLOR, moon_weight);
				cloud_light_energy = mix(sun_energy, moon_energy, moon_weight);
			}

			vec3 lower_plane_point = EYEDIR * (LOWER_PLANE_HEIGHT / EYEDIR.y);
			vec4 clouds = ray_march_clouds(
				lower_plane_point, EYEDIR,
				texture(RADIANCE, EYEDIR).rgb, SCREEN_UV,
				cloud_light_dir, cloud_light_color, cloud_light_energy, total_light_energy
			);
			COLOR.rgb = clouds.rgb;
			ALPHA     = clouds.a;
			ALPHA    *= smoothstep(
				clouds_alpha_lower_bound, clouds_alpha_upper_bound,
				dot(EYEDIR, vec3(0.0, 1.0, 0.0))
			);
		}

	} else {
		vec3 transmittance = QUARTER_RES_COLOR.rgb;
		vec3 radiance      = texture(RADIANCE, EYEDIR).rgb;

		float sun_mask = celestial_disc(EYEDIR, LIGHT0_DIRECTION, LIGHT0_SIZE * 0.5, sun_disc_feather);
		vec3  sundisc  = vec3(sun_mask) * transmittance * sundisc_intensity;

		vec3 moondisc = vec3(0.0);
		if (LIGHT1_ENABLED) {
			float moon_mask = celestial_disc(EYEDIR, LIGHT1_DIRECTION, LIGHT1_SIZE * 0.5, moon_disc_feather);
			moondisc = vec3(moon_mask) * transmittance * LIGHT1_COLOR * moon_disc_intensity;
		}

		vec3  stars = vec3(0.0);
		float night = 1.0;
		if (dim_stars_at_day) {
			night = smoothstep(0.3, -0.1, dot(LIGHT0_DIRECTION, vec3(0.0, 1.0, 0.0)));
		}
		if (!dim_stars_at_day || night > 0.01) {
			stars = procedural_stars(EYEDIR) * transmittance * night;
		}

		COLOR = radiance + sundisc + moondisc + stars;

		if (EYEDIR.y > 0.0 && use_cirrus) {
			float sun_energy = LIGHT0_ENERGY * smoothstep(-0.02, 0.05, LIGHT0_DIRECTION.y);
			vec3  cirrus_light_color  = LIGHT0_COLOR;
			float cirrus_light_energy = sun_energy;
			float cirrus_total_energy = sun_energy;

			if (LIGHT1_ENABLED) {
				float moon_energy = LIGHT1_ENERGY * smoothstep(-0.02, 0.05, LIGHT1_DIRECTION.y);
				cirrus_total_energy = sun_energy + moon_energy;
				float moon_weight   = moon_energy / max(sun_energy + moon_energy, 1e-4);
				cirrus_light_color  = mix(LIGHT0_COLOR, LIGHT1_COLOR, moon_weight);
				cirrus_light_energy = mix(sun_energy, moon_energy, moon_weight);
			}

			vec2  coords = EYEDIR.xz / EYEDIR.y;
			float cirrus_mask_val = smoothstep(
				cirrus_mask_treshold - cirrus_mask_feather,
				cirrus_mask_treshold + cirrus_mask_feather,
				texture(cirrus_mask_texture, coords * cirrus_mask_scale).r
			);
			vec2 cirrus_distortion = texture(
				cirrus_distortion_texture,
				coords * cirrus_distortion_scale + cirrus_distortion_offset
			).xy * cirrus_distortion_strength;
			float cirrus = smoothstep(
				cirrus_treshold - cirrus_feather,
				cirrus_treshold + cirrus_feather,
				texture(
					cirrus_texture,
					(coords * cirrus_scale + cirrus_offset) * cirrus_squish + cirrus_distortion
				).r
			) * cirrus_mask_val * cirrus_opacity * smoothstep(.5, 3.0, length(coords));

			vec3 cirrus_ambient_term = radiance * ambient_light_multiplier;
			vec3 cirrus_direct_term  = cirrus_light_color * cirrus_light_energy;
			vec3 cirrus_col          = cirrus * transmittance * (cirrus_ambient_term + cirrus_direct_term);
			cirrus_col = apply_scotopic_grading(cirrus_col, cirrus_total_energy);
			COLOR += cirrus_col;
		}

		vec4 clouds = HALF_RES_COLOR;
		COLOR = mix(COLOR, clouds.rgb, clouds.a);

		if (use_rainbow) COLOR += rainbow(EYEDIR, transmittance, clouds);

		if (use_debanding) COLOR += (rand(SKY_COORDS) - 0.5) * 0.001;
	}
}
Tags
Ambient, cloud, rainbow, sky
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from SEED

Related shaders

guest

0 Comments
Oldest
Newest Most Voted