300 lines
9.5 KiB
Plaintext
300 lines
9.5 KiB
Plaintext
// Copyright (c) 2023-2025 Cory Petkovsek and Contributors
|
|
// Copyright (c) 2021 J. Cuellar
|
|
|
|
shader_type spatial;
|
|
render_mode unshaded, depth_draw_never, cull_front, skip_vertex_transform;
|
|
|
|
// Color correction
|
|
uniform vec2 _color_correction_params;
|
|
uniform vec4 _ground_color: source_color;
|
|
uniform float _horizon_level;
|
|
|
|
// uniforms
|
|
uniform vec3 _sun_direction;
|
|
uniform vec3 _moon_direction;
|
|
|
|
uniform float _moon_size;
|
|
uniform mat3 _moon_matrix;
|
|
uniform mat3 _deep_space_matrix;
|
|
|
|
// Atmospheric Scattering
|
|
uniform float _atm_darkness;
|
|
uniform float _atm_sun_intensity;
|
|
uniform vec4 _atm_day_tint: source_color;
|
|
uniform vec4 _atm_horizon_light_tint: source_color;
|
|
uniform vec4 _atm_night_tint: source_color;
|
|
uniform vec3 _atm_level_params;
|
|
uniform float _atm_thickness;
|
|
|
|
// Sun mie phase
|
|
uniform vec4 _atm_sun_mie_tint: source_color;
|
|
uniform float _atm_sun_mie_intensity;
|
|
uniform vec4 _atm_moon_mie_tint: source_color;
|
|
uniform float _atm_moon_mie_intensity;
|
|
uniform vec3 _atm_beta_ray;
|
|
uniform vec3 _atm_beta_mie;
|
|
uniform vec3 _atm_sun_partial_mie_phase;
|
|
uniform vec3 _atm_moon_partial_mie_phase;
|
|
|
|
// Sun disk
|
|
uniform vec4 _sun_disk_color: source_color;
|
|
uniform float _sun_disk_intensity;
|
|
uniform float _sun_disk_size;
|
|
|
|
uniform vec4 _moon_color: source_color;
|
|
uniform sampler2D _moon_texture: source_color, repeat_disable;
|
|
|
|
// Background
|
|
uniform sampler2D _background_texture: source_color;
|
|
uniform vec4 _background_color: source_color;
|
|
|
|
// Stars Field
|
|
uniform vec4 _stars_field_color: source_color;
|
|
uniform sampler2D _stars_field_texture: source_color;
|
|
uniform float _stars_scintillation;
|
|
uniform float _stars_scintillation_speed;
|
|
|
|
uniform sampler2D _noise_tex: source_color;
|
|
|
|
// Clouds
|
|
uniform float _clouds_coverage;
|
|
uniform float _clouds_thickness;
|
|
uniform float _clouds_absorption;
|
|
uniform float _clouds_sky_tint_fade;
|
|
uniform float _clouds_intensity;
|
|
uniform float _clouds_size;
|
|
uniform vec2 _clouds_uv;
|
|
uniform float _clouds_speed;
|
|
uniform vec2 _clouds_direction;
|
|
uniform vec4 _clouds_day_color: source_color;
|
|
uniform vec4 _clouds_horizon_light_color: source_color;
|
|
uniform vec4 _clouds_night_color: source_color;
|
|
uniform sampler2D _clouds_texture;
|
|
|
|
|
|
// Inc
|
|
//------------------------------------------------------------------------------
|
|
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);
|
|
}
|
|
|
|
// pow3
|
|
vec3 contrastLevel(vec3 vec, float level){
|
|
return mix(vec, vec * vec * vec, level);
|
|
}
|
|
|
|
vec3 tonemapPhoto(vec3 color, float exposure, float level){
|
|
color.rgb *= exposure;
|
|
return mix(color.rgb, 1.0 - exp(-color.rgb), level);
|
|
}
|
|
|
|
vec2 equirectUV(vec3 norm){
|
|
vec2 ret;
|
|
ret.x = (atan(norm.x, norm.z) + kPI) * kINV_TAU;
|
|
ret.y = acos(norm.y) * kINV_PI;
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
float random(vec2 uv){
|
|
float ret = dot(uv, vec2(12.9898, 78.233));
|
|
return fract(43758.5453 * sin(ret));
|
|
}
|
|
*/
|
|
|
|
float disk(vec3 norm, vec3 coords, lowp float size){
|
|
float dist = length(norm - coords);
|
|
return 1.0 - step(size, dist);
|
|
}
|
|
|
|
// Atmosphere Inc
|
|
//------------------------------------------------------------------------------
|
|
const float RAYLEIGH_ZENITH_LENGTH = 8.4e3;
|
|
const float MIE_ZENITH_LENGTH = 1.25e3;
|
|
|
|
float rayleighPhase(float mu){
|
|
return k3PI16 * (1.0 + mu * mu);
|
|
}
|
|
|
|
float miePhase(float mu, vec3 partial){
|
|
return kPI4 * (partial.x) * (pow(partial.y - partial.z * mu, -1.5));
|
|
}
|
|
|
|
// Simplifield for more performance
|
|
void simpleOpticalDepth(float y, out float sr, out float sm){
|
|
y = max(0.03, y + 0.03) + _atm_level_params.y;
|
|
y = 1.0 / (y * _atm_level_params.x);
|
|
sr = y * RAYLEIGH_ZENITH_LENGTH;
|
|
sm = y * MIE_ZENITH_LENGTH;
|
|
}
|
|
|
|
// Paper based
|
|
void opticalDepth(float y, out float sr, out float sm){
|
|
y = max(0.0, y);
|
|
y = saturate(y * _atm_level_params.x);
|
|
|
|
float zenith = acos(y);
|
|
zenith = cos(zenith) + 0.15 * pow(93.885 - ((zenith * 180.0) / kPI), -1.253);
|
|
zenith = 1.0 / (zenith + _atm_level_params.y);
|
|
|
|
sr = zenith * RAYLEIGH_ZENITH_LENGTH;
|
|
sm = zenith * MIE_ZENITH_LENGTH;
|
|
}
|
|
|
|
vec3 atmosphericScattering(float sr, float sm, vec2 mu, vec3 mult){
|
|
vec3 betaMie = _atm_beta_mie;
|
|
vec3 betaRay = _atm_beta_ray * _atm_thickness;
|
|
|
|
vec3 extcFactor = saturateRGB(exp(-(betaRay * sr + betaMie * sm)));
|
|
|
|
float extcFF = mix(saturate(_atm_thickness * 0.5), 1.0, mult.x);
|
|
vec3 finalExtcFactor = mix(1.0 - extcFactor, (1.0 - extcFactor) * extcFactor, extcFF);
|
|
float rayleighPhase = rayleighPhase(mu.x);
|
|
vec3 BRT = betaRay * rayleighPhase;
|
|
vec3 BMT = betaMie * miePhase(mu.x, _atm_sun_partial_mie_phase);
|
|
BMT *= _atm_sun_mie_intensity * _atm_sun_mie_tint.rgb;
|
|
|
|
vec3 BRMT = (BRT + BMT) / (betaRay + betaMie);
|
|
vec3 scatter = _atm_sun_intensity * (BRMT * finalExtcFactor) * _atm_day_tint.rgb * mult.y;
|
|
scatter = mix(scatter, scatter * (1.0 - extcFactor), _atm_darkness);
|
|
|
|
vec3 lcol = mix(_atm_day_tint.rgb, _atm_horizon_light_tint.rgb, mult.x);
|
|
vec3 nscatter = (1.0 - extcFactor) * _atm_night_tint.rgb;
|
|
nscatter += miePhase(mu.y, _atm_moon_partial_mie_phase) *
|
|
_atm_moon_mie_tint.rgb * _atm_moon_mie_intensity * 0.005;
|
|
|
|
return (scatter * lcol) + nscatter;
|
|
}
|
|
|
|
// Clouds
|
|
//------------------------------------------------------------------------------
|
|
float noiseClouds(vec2 coords, vec2 offset){
|
|
float speed = TIME * _clouds_speed * .5; // .5 matches cumulus clouds
|
|
vec2 wind = offset * speed;
|
|
vec2 wind2 = (offset + offset) * speed;
|
|
float a = textureLod(_clouds_texture, coords.xy * _clouds_uv - wind, 0.0).r;
|
|
float b = textureLod(_clouds_texture, coords.xy * _clouds_uv - wind2, 0.0).r;
|
|
return ((a + b) * 0.5);
|
|
}
|
|
|
|
float cloudsDensity(vec2 p, vec2 offset){
|
|
float d = noiseClouds(p, offset);
|
|
float c = 1.0 - _clouds_coverage;
|
|
d = d - c;
|
|
//d += d;
|
|
return saturate(d);
|
|
}
|
|
|
|
vec4 renderClouds(vec3 pos){
|
|
pos.xy = pos.xz / pos.y;
|
|
pos *= _clouds_size;
|
|
float density = cloudsDensity(pos.xy, _clouds_direction);
|
|
float sh = saturate(exp(-_clouds_absorption * density));
|
|
float a = saturate(density * _clouds_thickness);
|
|
return vec4(vec3(density*sh) * _clouds_intensity, a);
|
|
}
|
|
|
|
// Varyings
|
|
//------------------------------------------------------------------------------
|
|
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.00000001;
|
|
|
|
world_pos = MODEL_MATRIX * vert;
|
|
moon_coords.xyz = (_moon_matrix * VERTEX) / _moon_size + 0.5;
|
|
moon_coords.w = dot(world_pos.xyz, _moon_direction.xyz);
|
|
deep_space_coords.xyz = (_deep_space_matrix * VERTEX).xyz;
|
|
|
|
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 col = vec3(0.0);
|
|
vec3 worldPos = normalize(world_pos).xyz;
|
|
vec3 cloudsPos = worldPos;
|
|
|
|
// Atmosphere
|
|
vec2 mu = vec2(dot(_sun_direction, worldPos), dot(_moon_direction, worldPos));
|
|
float sr, sm;
|
|
simpleOpticalDepth(worldPos.y + _atm_level_params.z + _horizon_level, sr, sm);
|
|
|
|
worldPos.y += _horizon_level;
|
|
float horizonBlend = saturate((worldPos.y - 0.03) * 3.0);
|
|
|
|
vec3 scatter = atmosphericScattering(sr, sm, mu.xy, angle_mult.xyz);
|
|
col.rgb += scatter.rgb;
|
|
|
|
// Near Space
|
|
vec3 nearSpace = vec3(0.0);
|
|
vec3 sunDisk = disk(worldPos, _sun_direction, _sun_disk_size) *
|
|
_sun_disk_color.rgb * scatter.rgb;
|
|
sunDisk *= _sun_disk_intensity;
|
|
|
|
// Moon
|
|
vec4 moon = texture(_moon_texture, vec2(-moon_coords.x+1.0, moon_coords.y));
|
|
moon.rgb = contrastLevel(moon.rgb * _moon_color.rgb, _moon_color.a);
|
|
moon *= saturate(moon_coords.w);
|
|
float moonMask = saturate(1.0 - moon.a);
|
|
nearSpace = moon.rgb + (sunDisk.rgb * moonMask);
|
|
col.rgb += nearSpace;
|
|
|
|
vec3 deepSpace = vec3(0.0);
|
|
vec2 deepSpaceUV = equirectUV(normalize(deep_space_coords));
|
|
|
|
// Background
|
|
vec3 deepSpaceBackground = textureLod(_background_texture, deepSpaceUV, 0.0).rgb;
|
|
deepSpaceBackground *= _background_color.rgb;
|
|
deepSpaceBackground = contrastLevel(deepSpaceBackground, _background_color.a);
|
|
deepSpace.rgb += deepSpaceBackground.rgb * moonMask;
|
|
|
|
// Stars Field
|
|
float starsScintillation = textureLod(_noise_tex, UV + (TIME * _stars_scintillation_speed), 0.0).r;
|
|
starsScintillation = mix(1.0, starsScintillation * 1.5, _stars_scintillation);
|
|
|
|
vec3 starsField = textureLod(_stars_field_texture, deepSpaceUV, 0.0).rgb * _stars_field_color.rgb;
|
|
starsField = saturateRGB(mix(starsField.rgb, starsField.rgb * starsScintillation, _stars_scintillation));
|
|
//deepSpace.rgb -= saturate(starsField.r*10.0);
|
|
deepSpace.rgb += starsField.rgb * moonMask;
|
|
deepSpace.rgb *= angle_mult.z;
|
|
col.rgb += deepSpace.rgb * horizonBlend;
|
|
|
|
// Clouds
|
|
vec4 clouds = renderClouds(cloudsPos);
|
|
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);
|
|
col.rgb = mix(col.rgb, clouds.rgb + mix(vec3(0.0), scatter, _clouds_sky_tint_fade), clouds.a);
|
|
col.rgb = mix(col.rgb, _ground_color.rgb * scatter, saturate((-worldPos.y - _atm_level_params.z)*100.0));
|
|
|
|
col.rgb = tonemapPhoto(col.rgb, _color_correction_params.y, _color_correction_params.x);
|
|
ALBEDO = col.rgb;
|
|
}
|