518 lines
19 KiB
Plaintext
518 lines
19 KiB
Plaintext
// Copyright (c) 2023-2025 Cory Petkovsek and Contributors
|
|
// Copyright (c) 2021 J. Cuellar
|
|
|
|
shader_type sky;
|
|
render_mode use_debanding;
|
|
|
|
group_uniforms general;
|
|
uniform bool sky_visible = true;
|
|
uniform vec2 color_correction = vec2(0.0, 1.0);
|
|
uniform vec4 ground_color: source_color = vec4(0.3, 0.3, 0.3, 1.0);
|
|
uniform float horizon_offset = 0.0;
|
|
|
|
group_uniforms atmosphere;
|
|
uniform float atm_darkness = 0.5;
|
|
uniform float atm_sun_intensity = 18.0;
|
|
uniform vec4 atm_day_tint: source_color = vec4(0.808, 0.91, 1.0, 1.0);
|
|
uniform vec4 atm_horizon_light_tint: source_color = vec4(0.98, 0.635, 0.463, 1.0);
|
|
uniform vec4 atm_night_tint: source_color = vec4 (0.041, 0.049, 0.061, 0.245);
|
|
uniform vec3 atm_level_params = vec3(1.0, 0.0, 0.0);
|
|
uniform float atm_thickness = 0.7;
|
|
uniform vec3 atm_beta_ray = vec3(0.00001, 0.00001, 0.00003);
|
|
uniform vec3 atm_beta_mie = vec3(0.00000003038); // Value computed by multiplying Mie, turbidity, and 0.000434.
|
|
|
|
group_uniforms sun_disk;
|
|
uniform vec4 sun_light_color: source_color = vec4(1.0);
|
|
uniform vec4 sun_disk_color: source_color = vec4(0.996, 0.541, 0.14, 1.0);
|
|
uniform float sun_disk_intensity = 2.0;
|
|
uniform float sun_disk_size = 0.015;
|
|
|
|
group_uniforms sun_mie;
|
|
uniform vec4 atm_sun_mie_tint: source_color = vec4(1.0);
|
|
uniform float atm_sun_mie_intensity = 1.0;
|
|
uniform vec3 atm_sun_partial_mie_phase = vec3(0.36, 1.64, 1.6);
|
|
|
|
group_uniforms moon;
|
|
uniform vec4 moon_color: source_color = vec4(1.0);
|
|
uniform sampler2D moon_texture: source_color, repeat_disable;
|
|
uniform vec3 moon_texture_alignment = vec3(7.0, 1.4, 4.8);
|
|
uniform bool moon_texture_flip_u;
|
|
uniform bool moon_texture_flip_v;
|
|
uniform float moon_size = 0.07;
|
|
|
|
group_uniforms moon_mie;
|
|
uniform vec4 atm_moon_mie_tint: source_color = vec4(0.137, 0.184, 0.292, 1.0);
|
|
uniform float atm_moon_mie_intensity = 0.17152;
|
|
uniform vec3 atm_moon_partial_mie_phase = vec3(0.36, 1.64, 1.6);
|
|
|
|
group_uniforms star_map;
|
|
uniform vec4 starmap_color: source_color = vec4(0.71, 0.71, 0.71, 0.855);
|
|
uniform sampler2D starmap_texture: source_color;
|
|
uniform bool starmap_flip_u = false;
|
|
uniform bool starmap_flip_v = false;
|
|
uniform vec3 starmap_alignment = vec3(2.68288, -0.25891, 0.40101);
|
|
uniform float star_rotation_offset = 9.38899;
|
|
uniform float star_rotation = 0.0; // For simulating Earth rotation.
|
|
uniform float star_tilt = 0.0; // For tilting the sky according to observer latitude in radians. (90° - latitude)
|
|
|
|
group_uniforms star_field;
|
|
uniform vec4 star_field_color: source_color = vec4(1.0);
|
|
uniform sampler2D star_field_texture: source_color;
|
|
uniform float star_scintillation = 0.75;
|
|
uniform float star_scintillation_speed = 0.01;
|
|
uniform sampler2D noise_tex: source_color;
|
|
|
|
/* Sky alignment values for a star map that is in galactic coordinates. Works for most star maps.
|
|
X: 2.6555
|
|
Y: -0.23935
|
|
Z: 0.4505
|
|
|
|
These alignment values are consistent with a sky view from the North Pole (latitude zero)
|
|
at midnight. The positions of Polaris, Vega, Rigel, and Alpha Centauri confirmed
|
|
through various sources and calculations.
|
|
*/
|
|
|
|
group_uniforms clouds;
|
|
uniform vec4 clouds_night_color: source_color = vec4(0.09, 0.094, 0.129, 1.0);
|
|
|
|
group_uniforms cirrus_clouds;
|
|
uniform bool cirrus_visible = true;
|
|
uniform float cirrus_intensity = 2.0;
|
|
uniform float cirrus_coverage = 0.5;
|
|
uniform float cirrus_thickness = 10.0;
|
|
uniform float cirrus_absorption = 2.0;
|
|
uniform float cirrus_sky_tint_fade = 0.5;
|
|
uniform float cirrus_size = 1.0;
|
|
uniform vec2 cirrus_uv = vec2(0.16, 0.11);
|
|
uniform vec2 cirrus_position1 = vec2(0.0);
|
|
uniform vec2 cirrus_position2 = vec2(0.0);
|
|
uniform sampler2D cirrus_texture;
|
|
|
|
group_uniforms cumulus_clouds;
|
|
uniform bool cumulus_visible = true;
|
|
uniform float cumulus_intensity = 0.6;
|
|
uniform float cumulus_coverage = 0.55;
|
|
uniform float cumulus_thickness = 0.0243;
|
|
uniform float cumulus_absorption = 2.0;
|
|
uniform float cumulus_noise_freq = 2.7;
|
|
uniform float cumulus_sky_tint_fade = 0.0;
|
|
uniform float cumulus_size = 0.5;
|
|
uniform vec2 cumulus_position = vec2(0.0);
|
|
uniform sampler2D cumulus_texture;
|
|
uniform vec3 cumulus_partial_mie_phase = vec3(0.95756, 1.04244, 0.412);
|
|
uniform float cumulus_mie_intensity = 1.0;
|
|
|
|
group_uniforms overlays;
|
|
uniform bool show_azimuthal_grid = false;
|
|
uniform vec4 azimuthal_grid_color : source_color = vec4(.871, .722, .529, 1.);
|
|
uniform float azimuthal_grid_rotation_offset = 0.03;
|
|
uniform bool show_equatorial_grid = false;
|
|
uniform vec4 equatorial_grid_color : source_color = vec4(0., .75, 1., 1.);
|
|
uniform float equatorial_grid_rotation_offset = 0.03;
|
|
|
|
group_uniforms transform_matrices;
|
|
uniform mat3 moon_matrix; // Calculated externally via GDScript.
|
|
|
|
#include "Common.gdshaderinc"
|
|
|
|
// Provides a transformation matrix when passed a vec3.
|
|
mat3 create_rotation_matrix(vec3 r) {
|
|
float c1 = cos(r.x), s1 = sin(r.x);
|
|
float c2 = cos(r.y), s2 = sin(r.y);
|
|
float c3 = cos(r.z), s3 = sin(r.z);
|
|
|
|
mat3 rotX = mat3(
|
|
vec3(1.0, 0.0, 0.0),
|
|
vec3(0.0, c1, -s1),
|
|
vec3(0.0, s1, c1)
|
|
);
|
|
|
|
mat3 rotY = mat3(
|
|
vec3(c2, 0.0, s2),
|
|
vec3(0.0, 1.0, 0.0),
|
|
vec3(-s2, 0.0, c2)
|
|
);
|
|
|
|
mat3 rotZ = mat3(
|
|
vec3(c3, -s3, 0.0),
|
|
vec3(s3, c3, 0.0),
|
|
vec3(0.0, 0.0, 1.0)
|
|
);
|
|
|
|
return rotZ * rotY * rotX; // Combine rotations in ZYX order
|
|
}
|
|
|
|
vec2 calc_equirect_uv(vec3 norm) {
|
|
float flipu = starmap_flip_u ? -1.0 : 1.0;
|
|
float flipv = starmap_flip_v ? -1.0 : 1.0;
|
|
float u = flipu * ((atan(norm.y, norm.x) + PI) * INV_TAU); // 0 to 1 horizontally
|
|
float v = -flipv * (acos(norm.z) * INV_PI); // 0 (north pole) to 1 (south pole)
|
|
return vec2(u, v);
|
|
}
|
|
|
|
vec3 sample_moon_texture(vec3 dir) {
|
|
dir = moon_matrix * dir * create_rotation_matrix(moon_texture_alignment);
|
|
dir.x = -dir.x;
|
|
dir.z = -dir.z;
|
|
float flipu = moon_texture_flip_u ? 1.0 : -1.0;
|
|
float flipv = moon_texture_flip_v ? 1.0 : -1.0;
|
|
float u = 0.5 + flipu * atan(dir.z, dir.x) * INV_TAU; // Longitude
|
|
float v = 0.5 + flipv * asin(dir.y) * INV_PI; // Latitude
|
|
return texture(moon_texture, vec2(u, v)).rgb;
|
|
}
|
|
|
|
float calc_disk_mask(vec3 norm, vec3 coords, lowp float size) {
|
|
float dist = length(norm - coords);
|
|
return 1.0 - step(size, dist);
|
|
}
|
|
|
|
float map_range(float value, float from_min, float from_max, float to_min, float to_max) {
|
|
return to_min + (value - from_min) * (to_max - to_min) / (from_max - from_min);
|
|
}
|
|
|
|
bool ray_sphere_intersect(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;
|
|
float valid = step(0.0, d); // 1.0 if d >= 0.0, else 0.0
|
|
d = sqrt(max(d, 0.0)); // Prevent sqrt of negative numbers
|
|
a *= 2.0;
|
|
float t1 = 0.5 * (-b + d);
|
|
float t2 = 0.5 * (-b - d);
|
|
float t_min = min(t1, t2); // Select the smallest intersection
|
|
t = mix(t2, t1, step(t2, t1) * step(0.0, t1)); // Use t1 if t2 < t1 and t1 >= 0, else t2
|
|
t = mix(0.0, t, step(0.0, t) * valid); // Invalidate if t < 0 or d < 0
|
|
nrm = mix(vec3(0.0), origin + t * dir, step(0.0, t) * valid); // Set nrm only if valid
|
|
return bool(step(0.0, t) * valid);
|
|
}
|
|
|
|
// For rendering the moon. This function courtesy of Kelvin van Hoorn.
|
|
// https://kelvinvanhoorn.com/2024/12/07/skybox-tutorial-godot/
|
|
float simple_sphere_intersect(vec3 ray_dir, vec3 sphere_pos, float radius) {
|
|
vec3 oc = -sphere_pos;
|
|
float b = dot(oc, ray_dir);
|
|
float c = dot(oc, oc) - radius * radius;
|
|
float h = b * b - c;
|
|
float valid = step(0.0, h); // 1.0 if h >= 0.0, else 0.0
|
|
h = sqrt(max(h, 0.0)); // Ensure sqrt is non-negative
|
|
return mix(-1.0, -b - h, valid);
|
|
}
|
|
|
|
// Atmosphere
|
|
//------------------------------------------------------------------------------
|
|
|
|
vec3 calc_atmospheric_scatter(float sr, float sm, vec2 mu, vec3 mult) {
|
|
vec3 beta_mie = atm_beta_mie;
|
|
vec3 beta_ray = atm_beta_ray * atm_thickness;
|
|
|
|
vec3 extc_factor = clamp_rgb_to_unit(exp(-(beta_ray * sr + beta_mie * sm)));
|
|
|
|
float extc_ff = mix(clamp_to_unit(atm_thickness * 0.5), 1.0, mult.x);
|
|
vec3 final_extc_factor = mix(1.0 - extc_factor, (1.0 - extc_factor) * extc_factor, extc_ff);
|
|
float rayleigh_phase = calc_rayleigh_phase(mu.x);
|
|
vec3 BRT = beta_ray * rayleigh_phase;
|
|
vec3 BMT = beta_mie * calc_mie_phase(mu.x, atm_sun_partial_mie_phase);
|
|
BMT *= atm_sun_mie_intensity * atm_sun_mie_tint.rgb;
|
|
|
|
vec3 BRMT = (BRT + BMT) / (beta_ray + beta_mie);
|
|
vec3 scatter = atm_sun_intensity * (BRMT * final_extc_factor) * atm_day_tint.rgb * mult.y;
|
|
scatter = mix(scatter, scatter * (1.0 - extc_factor), atm_darkness);
|
|
|
|
vec3 lcol = mix(atm_day_tint.rgb, atm_horizon_light_tint.rgb, mult.x);
|
|
vec3 nscatter = (1.0 - extc_factor) * atm_night_tint.rgb;
|
|
nscatter += calc_mie_phase(mu.y, atm_moon_partial_mie_phase) *
|
|
atm_moon_mie_tint.rgb * atm_moon_mie_intensity * 0.005;
|
|
|
|
return (scatter * lcol) + nscatter;
|
|
}
|
|
|
|
// Clouds
|
|
//------------------------------------------------------------------------------
|
|
const int CUMULUS_STEP = 10;
|
|
|
|
float sample_cirrus_noise(vec2 coords) {
|
|
float a = textureLod(cirrus_texture, coords.xy * cirrus_uv + cirrus_position1, 0.0).r;
|
|
float b = textureLod(cirrus_texture, coords.xy * cirrus_uv + cirrus_position2, 0.0).r;
|
|
return ((a + b) * 0.5);
|
|
}
|
|
|
|
float sample_cumulus_noise(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(cumulus_texture, uv.xy, 0.0).r;
|
|
float x2 = textureLod(cumulus_texture, uv.zw, 0.0).r;
|
|
return mix(x1, x2, fract(pos.z));
|
|
}
|
|
|
|
float calc_cumulus_fbm(vec3 p, float l) {
|
|
float ret;
|
|
ret = 0.51749673 * sample_cumulus_noise(p);
|
|
p *= l;
|
|
ret += 0.25584929 * sample_cumulus_noise(p);
|
|
p *= l;
|
|
ret += 0.12527603 * sample_cumulus_noise(p);
|
|
p *= l;
|
|
ret += 0.06255931 * sample_cumulus_noise(p);
|
|
return ret;
|
|
}
|
|
|
|
float calc_cirrus_density(vec2 p) {
|
|
float d = sample_cirrus_noise(p);
|
|
float c = 1.0 - cirrus_coverage;
|
|
d = d - c;
|
|
return clamp_to_unit(d);
|
|
}
|
|
|
|
float calc_cumulus_density(vec3 p, vec3 offset, float t) {
|
|
vec3 pos = p * 0.0212242 - offset;
|
|
float dens = calc_cumulus_fbm(pos, cumulus_noise_freq);
|
|
dens += dens;
|
|
|
|
float cov = 1.0 - cumulus_coverage;
|
|
cov = smoothstep(0.00, (cov * 3.5) + t, dens);
|
|
dens *= cov;
|
|
dens = map_range(dens, 1.0 - cov, 1.0, 0.0, 1.0);
|
|
|
|
return clamp_to_unit(dens);
|
|
}
|
|
|
|
vec4 render_cirrus_clouds(vec3 pos) {
|
|
pos.xy = pos.xz / pos.y;
|
|
pos *= cirrus_size;
|
|
float density = calc_cirrus_density(pos.xy);
|
|
float sh = clamp_to_unit(exp(-cirrus_absorption * density));
|
|
float a = clamp_to_unit(density * cirrus_thickness);
|
|
return vec4(vec3(density*sh) * cirrus_intensity, a);
|
|
}
|
|
|
|
vec4 render_cumulus_clouds(vec3 ro, vec3 rd, float am, vec3 sun_pos, vec3 moon_pos) {
|
|
vec4 ret = vec4(0.);
|
|
vec3 wind = -vec3(cumulus_position.x, 0.0, cumulus_position.y);
|
|
float a = 0.0;
|
|
|
|
// n and tt doesnt need to be initialized since it would be set by ray_sphere_intersect
|
|
vec3 n; float tt;
|
|
if (ray_sphere_intersect(500., ro, rd, tt, n)) {
|
|
float march_step = float(CUMULUS_STEP) * cumulus_thickness;
|
|
vec3 dir_step = rd / rd.y * march_step;
|
|
vec3 pos = n * cumulus_size;
|
|
|
|
vec2 mu = vec2(dot(sun_pos, rd), dot(moon_pos, rd));
|
|
vec3 mph = ((calc_mie_phase(mu.x, cumulus_partial_mie_phase) * atm_sun_mie_tint.rgb) +
|
|
calc_mie_phase(mu.y, cumulus_partial_mie_phase) * am);
|
|
|
|
vec4 t = vec4(1.0);
|
|
t.rgb += (mph.rgb * cumulus_mie_intensity);
|
|
|
|
for(int i = 0; i < CUMULUS_STEP; i++) {
|
|
float h = float(i) * 0.1; // / float(kCLOUDS_STEP);
|
|
float density = calc_cumulus_density(pos, wind, h);
|
|
float sh = clamp_to_unit(exp(-cumulus_absorption * density * march_step));
|
|
t *= sh;
|
|
ret += (t * (exp(h) * 0.571428571) * density * march_step);
|
|
a += (1.0 - sh) * (1.0 - a);
|
|
pos += dir_step;
|
|
}
|
|
return vec4(ret.rgb * cumulus_intensity, a);
|
|
}
|
|
return vec4(ret.rgb * cumulus_intensity, a);
|
|
}
|
|
|
|
// Main
|
|
//------------------------------------------------------------------------------
|
|
|
|
vec3 render_sky(vec3 world_pos, vec3 clouds_pos, vec3 sun_pos, vec3 moon_pos, float p_time) {
|
|
vec3 col = vec3(0.0);
|
|
|
|
vec4 angle_mult;
|
|
angle_mult.x = clamp_to_unit(1.0 - sun_pos.y);
|
|
angle_mult.y = clamp_to_unit(sun_pos.y + 0.45);
|
|
angle_mult.z = clamp_to_unit(-sun_pos.y + 0.30);
|
|
angle_mult.w = clamp_to_unit(-sun_pos.y + 0.60);
|
|
|
|
// Atmosphere
|
|
vec2 mu = vec2(dot(sun_pos, world_pos), dot(moon_pos, world_pos));
|
|
float sr, sm;
|
|
calc_simple_optical_depth(world_pos.y + atm_level_params.z - horizon_offset, sr, sm, atm_level_params.xy);
|
|
|
|
world_pos.y -= horizon_offset;
|
|
float horizonBlend = clamp_to_unit((world_pos.y - 0.03) * 3.0);
|
|
float horizonBlendCumulus = clamp_to_unit((world_pos.y + 0.01) * 50.0);
|
|
|
|
vec3 scatter = calc_atmospheric_scatter(sr, sm, mu.xy, angle_mult.xyz);
|
|
col.rgb += scatter.rgb;
|
|
|
|
// Sun
|
|
vec3 sun_disk = calc_disk_mask(world_pos, sun_pos, sun_disk_size) * sun_disk_color.rgb * scatter.rgb;
|
|
sun_disk *= sun_disk_intensity;
|
|
|
|
// Moon
|
|
float moon_intersect = simple_sphere_intersect(world_pos, moon_pos, moon_size);
|
|
float moon_mask = moon_intersect > (-1. + sqrt(moon_size)) ? 1.0 : 0.0;
|
|
vec3 moon_normal = normalize(world_pos * moon_intersect - moon_pos);
|
|
|
|
float moon_ndotl = clamp(dot(moon_normal, sun_pos), 0.0, 1.0);
|
|
vec3 moon_tex = sample_moon_texture(moon_normal);
|
|
vec3 moon_output = moon_mask * moon_ndotl * exp2(1.0) * moon_tex * moon_color.rgb;
|
|
float moonMask = (1.0 - moon_mask);
|
|
|
|
// Deep space
|
|
|
|
// Tilt the sky along the X-axis.
|
|
mat3 tilt = create_rotation_matrix(vec3(star_tilt, 0.0, 0.0));
|
|
|
|
// Rotation around Y-axis. For simulating Earth's rotation.
|
|
mat3 rotation = create_rotation_matrix(vec3(0.0, star_rotation + star_rotation_offset, 0.0));
|
|
|
|
// Initial XYZ rotation for alignment.
|
|
mat3 alignment_xyz = create_rotation_matrix(starmap_alignment);
|
|
|
|
// Combine everything together to get the desired alignment.
|
|
vec3 final_alignment = normalize(alignment_xyz * rotation * tilt * world_pos);
|
|
|
|
// Now generate UV coordinates for the texture.
|
|
vec2 deep_space_uv = calc_equirect_uv(normalize(final_alignment));
|
|
|
|
// Star map
|
|
vec3 deep_space_background = textureLod(starmap_texture, deep_space_uv, 0.0).rgb;
|
|
deep_space_background *= starmap_color.rgb;
|
|
deep_space_background = adjust_contrast(deep_space_background, starmap_color.a);
|
|
vec3 deep_space = deep_space_background.rgb * moonMask + moon_output;
|
|
|
|
// Star Field
|
|
float star_scint = textureLod(noise_tex, deep_space_uv + (p_time * star_scintillation_speed), 0.0).r;
|
|
star_scint = mix(1.0, star_scint * 1.5, star_scintillation);
|
|
|
|
vec3 star_field = textureLod(star_field_texture, deep_space_uv, 0.0).rgb * star_field_color.rgb;
|
|
star_field = clamp_rgb_to_unit(mix(star_field.rgb, star_field.rgb * star_scint, star_scintillation));
|
|
star_field = clamp_rgb_to_unit(star_field.rgb);
|
|
//deep_space.rgb -= clamp_to_unit(star_field.r * 10.0);
|
|
deep_space.rgb += star_field.rgb * moonMask;
|
|
deep_space.rgb *= angle_mult.z;
|
|
col.rgb += sun_disk.rgb + deep_space.rgb * horizonBlend;
|
|
|
|
// Clouds
|
|
if (cirrus_visible) {
|
|
vec4 cirrus_clouds = render_cirrus_clouds(clouds_pos);
|
|
cirrus_clouds.a = clamp_to_unit(cirrus_clouds.a);
|
|
vec3 cloud_tint = sun_light_color.rgb;
|
|
cloud_tint = mix(cloud_tint, clouds_night_color.rgb, angle_mult.w);
|
|
cirrus_clouds.rgb *= cloud_tint * cirrus_intensity;
|
|
cirrus_clouds.a = mix(0.0, cirrus_clouds.a, horizonBlend);
|
|
col.rgb = mix(col.rgb, cirrus_clouds.rgb + mix(vec3(0.0), scatter, cirrus_sky_tint_fade), cirrus_clouds.a);
|
|
}
|
|
|
|
if (cumulus_visible) {
|
|
vec4 cumulus_clouds = render_cumulus_clouds(vec3(0.0), clouds_pos, angle_mult.z, sun_pos, moon_pos);
|
|
cumulus_clouds.a = clamp_to_unit(cumulus_clouds.a);
|
|
vec3 cloud_tint = sun_light_color.rgb;
|
|
cloud_tint = mix(cloud_tint, clouds_night_color.rgb, angle_mult.w);
|
|
cumulus_clouds.rgb *= cloud_tint * cumulus_intensity;
|
|
cumulus_clouds.a = mix(0.0, cumulus_clouds.a, horizonBlend);
|
|
col.rgb = mix(col.rgb, cumulus_clouds.rgb + mix(vec3(0.0), scatter, cumulus_sky_tint_fade), cumulus_clouds.a);
|
|
}
|
|
|
|
col.rgb = mix(col.rgb, ground_color.rgb * scatter, clamp_to_unit((-world_pos.y - atm_level_params.z) * 100.0));
|
|
col.rgb = apply_photo_tonemap(col.rgb, color_correction.y, color_correction.x);
|
|
return col;
|
|
}
|
|
|
|
vec4 create_axis_angle_quat(vec3 axis, float angle) {
|
|
float s = sin(angle * 0.5);
|
|
return vec4(axis * s, cos(angle * 0.5));
|
|
}
|
|
|
|
vec3 rotate_vector_by_quat(vec3 v, vec4 q) {
|
|
vec3 t = 2.0 * cross(q.xyz, v);
|
|
return v + q.w * t + cross(q.xyz, t);
|
|
}
|
|
|
|
vec3 align_and_rotate_vector(vec3 dir, vec3 target, float rotation_angle) {
|
|
vec3 z_axis = vec3(0.0, 0.0, 1.0); // Original grid alignment
|
|
|
|
// First, align Z-axis with target (Polaris)
|
|
target = normalize(target);
|
|
vec3 axis = cross(z_axis, target);
|
|
float angle = acos(dot(z_axis, target));
|
|
float valid = step(0.0001, length(axis)); // 1.0 if length(axis) >= 0.0001
|
|
axis = normalize(axis);
|
|
vec4 align_quat = create_axis_angle_quat(axis, angle);
|
|
dir = mix(dir, rotate_vector_by_quat(dir, align_quat), valid);
|
|
vec4 rot_quat = create_axis_angle_quat(vec3(0.0, 0.0, 1.0), rotation_angle);
|
|
dir = mix(dir, rotate_vector_by_quat(dir, rot_quat), valid);
|
|
return dir;
|
|
}
|
|
|
|
void render_grid(vec3 dir, vec3 pole_dir, float rotation_angle, vec4 line_color, float grid_spacing, float line_thickness, inout vec3 color) {
|
|
float spacing = max(grid_spacing, 0.001);
|
|
float thickness = max(line_thickness, 0.0001);
|
|
|
|
// Rotate dir with sidereal motion and align with pole_dir
|
|
dir = align_and_rotate_vector(dir, pole_dir, rotation_angle);
|
|
|
|
// Latitude / Circles / Theta Spherical coordinates
|
|
float theta = acos(dir.z);
|
|
float theta_deriv = fwidth(theta);
|
|
float circle_thickness = max(thickness, theta_deriv);
|
|
float circle = mod(theta, spacing);
|
|
float circle_line = 1.0 - smoothstep(0.0, circle_thickness * 1.5, abs(circle - circle_thickness * 0.5));
|
|
circle_line *= clamp_to_unit(thickness / circle_thickness);
|
|
|
|
// Add poles
|
|
float pole_thickness = circle_thickness;
|
|
float north_pole = 1.0 - smoothstep(0.0, pole_thickness, theta);
|
|
float south_pole = 1.0 - smoothstep(0.0, pole_thickness, abs(theta - PI));
|
|
circle_line = max(circle_line, max(north_pole, south_pole));
|
|
|
|
// Darken Lat at poles
|
|
float circle_adjust = sin(theta);
|
|
circle_line *= clamp(circle_adjust, 0.2, 1.0);
|
|
|
|
// Longitude / Radial lines / Phi Spherical coordinates
|
|
float phi = atan(dir.y, dir.x);
|
|
float phi_deriv = fwidth(phi);
|
|
float radial_thickness = max(thickness, phi_deriv);
|
|
float radial = mod(phi + PI, spacing); // PI w/ less precision to remove moire
|
|
float radial_line = 1.0 - smoothstep(0.0, radial_thickness * 1.5, abs(radial - radial_thickness));
|
|
radial_line *= clamp_to_unit(thickness / radial_thickness);
|
|
|
|
float grid = max(radial_line, circle_line);
|
|
color += line_color.rgb * line_color.a * grid;
|
|
}
|
|
|
|
void sky() {
|
|
float current_time = TIME;
|
|
vec3 col = vec3(0.0); // Set up the initial sky color which will be added to later to produce the final result.
|
|
vec3 world_pos = EYEDIR; // Original shader set this up in the vertex() function. For sky shaders the overall equivalent is EYEDIR.
|
|
vec3 clouds_pos = EYEDIR; // The same is used for cloud rendering.
|
|
vec3 sun_pos = LIGHT0_DIRECTION; // Redefined from now-deprecated _sun_direction.
|
|
vec3 moon_pos = LIGHT1_DIRECTION; // Redefined from now-deprecated _moon_direction.
|
|
|
|
if (sky_visible) {
|
|
col = render_sky(world_pos, clouds_pos, sun_pos, moon_pos, current_time);
|
|
}
|
|
|
|
// Draw overlay grids
|
|
{
|
|
float grid_thickness = 0.0002;
|
|
float grid_spacing = 0.261799; // 15 degrees
|
|
vec3 zenith_dir = vec3(0.0, 1.0, 0.0); // Y-axis aligned azimuthal
|
|
vec3 north_celestial_pole = create_rotation_matrix(vec3(star_tilt, 0.0, 0.0)) * zenith_dir;
|
|
float rotation_angle = star_rotation + star_rotation_offset;
|
|
if (show_azimuthal_grid) {
|
|
render_grid(EYEDIR, zenith_dir, azimuthal_grid_rotation_offset, azimuthal_grid_color, grid_spacing, grid_thickness, col);
|
|
}
|
|
if (show_equatorial_grid) {
|
|
render_grid(EYEDIR, north_celestial_pole, rotation_angle + equatorial_grid_rotation_offset, equatorial_grid_color, grid_spacing, grid_thickness, col);
|
|
}
|
|
}
|
|
|
|
COLOR = col.rgb;
|
|
}
|