3d-rpg/addons/sky_3d/shaders/AtmFog.gdshader
2025-05-18 12:36:32 -06:00

212 lines
6.9 KiB
Plaintext

// Copyright (c) 2023-2025 Cory Petkovsek and Contributors
// Copyright (c) 2021 J. Cuellar
shader_type spatial;
render_mode blend_mix, cull_disabled, unshaded;
uniform vec2 _color_correction_params;
uniform float _fog_density = .0001;
uniform float _fog_rayleigh_depth = .115;
uniform float _fog_mie_depth = 0.;
uniform float _fog_falloff = 3.;
uniform float _fog_start = 0.;
uniform float _fog_end = 1000.;
uniform vec3 _sun_direction = vec3(.25, -.25, .25);
uniform vec3 _moon_direction = vec3(.45, -.25, .45);
uniform float _atm_darkness = .5;
uniform float _atm_sun_intensity = 30.;
uniform vec4 _atm_day_tint: source_color = vec4(.78, .85, .98, 1.);
uniform vec4 _atm_horizon_light_tint: source_color = vec4(.98, .73, .49, 1.);
uniform vec4 _atm_night_tint: source_color = vec4(.16, .2, .25, 1.);
uniform vec3 _atm_level_params = vec3(1., 0., 0.);
uniform float _atm_thickness = .7;
uniform vec3 _atm_beta_ray;
uniform vec3 _atm_beta_mie;
uniform vec3 _atm_sun_partial_mie_phase;
uniform vec4 _atm_sun_mie_tint: source_color = vec4(1.);
uniform float _atm_sun_mie_intensity = 1.;
uniform vec3 _atm_moon_partial_mie_phase;
uniform vec4 _atm_moon_mie_tint: source_color = vec4(.13, .18, .29, 1.);
uniform float _atm_moon_mie_intensity = .7;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
// 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;
}
// 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, float depth){
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 * saturate(depth * _fog_rayleigh_depth);
vec3 BMT = betaMie * miePhase(mu.x, _atm_sun_partial_mie_phase);
BMT *= _atm_sun_mie_intensity * _atm_sun_mie_tint.rgb * saturate(depth * _fog_mie_depth);
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 * saturate(depth * _fog_rayleigh_depth);
nscatter += miePhase(mu.y, _atm_moon_partial_mie_phase) *
_atm_moon_mie_tint.rgb * _atm_moon_mie_intensity * 0.005 * saturate(depth * _fog_mie_depth);
return (scatter * lcol) + nscatter;
}
// Fog
//------------------------------------------------------------------------------
float fogExp(float depth, float density){
return 1.0 - saturate(exp2(-depth * density));
}
float fogFalloff(float y, float zeroLevel, float falloff){
return saturate(exp(-(y + zeroLevel) * falloff));
}
float fogDistance(float depth){
float d = depth;
d = (_fog_end - d) / (_fog_end - _fog_start);
return saturate(1.0 - d);
}
void computeCoords(vec2 uv, float depth, mat4 camMat, mat4 invProjMat,
out vec3 viewDir, out vec3 worldPos){
vec3 ndc = vec3(uv * 2.0 - 1.0, depth);
// ViewDir
vec4 view = invProjMat * vec4(ndc, 1.0);
viewDir = view.xyz / view.w;
// worldPos
view = camMat * view;
view.xyz /= view.w;
view.xyz -= (camMat * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
worldPos = view.xyz;
}
// Varyings
//------------------------------------------------------------------------------
varying mat4 camera_matrix;
varying vec4 angle_mult;
varying flat int angle;
void vertex(){
POSITION = vec4(VERTEX.xy, 1.0, 1.0);
angle = 0; //ignore; without this the line below errors in 4.3-stable
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);
camera_matrix = INV_VIEW_MATRIX;
}
void fragment(){
float depthRaw = texture(DEPTH_TEXTURE, SCREEN_UV).r;
vec3 view; vec3 worldPos;
computeCoords(SCREEN_UV, depthRaw, camera_matrix, INV_PROJECTION_MATRIX, view, worldPos);
worldPos = normalize(worldPos);
float linearDepth = -view.z;
float fogFactor = fogExp(linearDepth, _fog_density);
fogFactor *= fogFalloff(worldPos.y, 0.0, _fog_falloff);
fogFactor *= fogDistance(linearDepth);
vec2 mu = vec2(dot(_sun_direction, worldPos), dot(_moon_direction, worldPos));
float sr; float sm; simpleOpticalDepth(worldPos.y + _atm_level_params.z, sr, sm);
vec3 scatter = atmosphericScattering(sr, sm, mu.xy, angle_mult.xyz, linearDepth);
vec3 tint = scatter;
vec4 fogColor = vec4(tint.rgb, fogFactor);
fogColor = vec4((fogColor.rgb), saturate(fogColor.a));
fogColor.rgb = tonemapPhoto(fogColor.rgb, _color_correction_params.y, _color_correction_params.x);
ALBEDO = fogColor.rgb;
ALPHA = fogColor.a;
//ALPHA = (depthRaw) < 0.999999999999 ? fogColor.a: 0.0; // Exclude sky.
}