142 lines
No EOL
4.3 KiB
Text
142 lines
No EOL
4.3 KiB
Text
include "pipelines/common.glsl"
|
|
|
|
vertex_shader [[
|
|
|
|
layout (location = 0) out vec2 v_uv;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = fullscreenQuad(gl_VertexID, v_uv);
|
|
}
|
|
]]
|
|
|
|
|
|
fragment_shader [[
|
|
layout (location = 0) in vec2 v_uv;
|
|
layout (location = 0) out vec4 o_color;
|
|
|
|
vec3 air_color = vec3(0.18867780436772762, 0.4978442963618773, 0.6616065586417131);
|
|
|
|
float phase(float alpha, float g)
|
|
{
|
|
float a = 3.0*(1.0-g*g);
|
|
float b = 2.0*(2.0+g*g);
|
|
float c = 1.0+alpha*alpha;
|
|
float d = pow(1.0+g*g-2.0*g*alpha, 1.5);
|
|
return (a/b)*(c/d);
|
|
}
|
|
|
|
|
|
float atmospheric_depth(vec3 position, vec3 dir)
|
|
{
|
|
float a = dot(dir, dir);
|
|
float b = 2.0*dot(dir, position);
|
|
float c = dot(position, position)-1.0;
|
|
float det = b*b-4.0*a*c;
|
|
float detSqrt = sqrt(det);
|
|
float q = (-b - detSqrt)/2.0;
|
|
float t1 = c/q;
|
|
return t1;
|
|
}
|
|
|
|
|
|
float horizon_extinction(vec3 position, vec3 dir, float radius)
|
|
{
|
|
float u = dot(dir, -position);
|
|
if(u<0.0){
|
|
return 1.0;
|
|
}
|
|
vec3 near = position + u*dir;
|
|
if(length(near) < radius){
|
|
return 0.0;
|
|
}
|
|
else{
|
|
vec3 v2 = normalize(near)*radius - position;
|
|
float diff = acos(dot(normalize(v2), dir));
|
|
return smoothstep(0.0, 1.0, pow(diff*2.0, 3.0));
|
|
}
|
|
}
|
|
|
|
vec3 absorb(float dist, vec3 color, float factor)
|
|
{
|
|
return color-color*pow(air_color.rgb, vec3(factor/dist));
|
|
}
|
|
|
|
vec3 getWorldNormal(vec2 frag_coord)
|
|
{
|
|
float z = 1;
|
|
#ifdef _ORIGIN_BOTTOM_LEFT
|
|
vec4 posProj = vec4(frag_coord * 2 - 1, z, 1.0);
|
|
#else
|
|
vec4 posProj = vec4(vec2(frag_coord.x, -frag_coord.y) * 2 - 1, z, 1.0);
|
|
#endif
|
|
vec4 wpos = u_camera_inv_view_projection * posProj;
|
|
wpos /= wpos.w;
|
|
vec3 view = (u_camera_inv_view * vec4(0.0, 0.0, 0.0, 1.0)).xyz - wpos.xyz;
|
|
|
|
return -normalize(view);
|
|
}
|
|
|
|
float getFogFactorSky(float cam_height, vec3 eye_dir, float fog_density, float fog_bottom, float fog_height)
|
|
{
|
|
if(eye_dir.y == 0) return 1.0;
|
|
float to_top = max(0, (fog_bottom + fog_height) - cam_height);
|
|
|
|
float avg_y = (fog_bottom + fog_height + cam_height) * 0.5;
|
|
float avg_density = fog_density * clamp(1 - (avg_y - fog_bottom) / fog_height, 0, 1);
|
|
float res = exp(-pow(avg_density * to_top / eye_dir.y, 2));
|
|
res = 1 - clamp(res - (1-min(0.2, eye_dir.y)*5), 0, 1);
|
|
return res;
|
|
}
|
|
|
|
void main()
|
|
{
|
|
const vec3 strength = vec3(0.028, 0.139, 0.0264);
|
|
const vec3 brightness = vec3(5, 0.15, 200);
|
|
const float rayleigh_collection_power = 0.51f;
|
|
const float mie_collection_power = 0.39f;
|
|
const float mie_distribution = 0.13f;
|
|
|
|
const float sun_size = 15;
|
|
const float surface_height = 0.993;
|
|
const float intensity = 1.8;
|
|
const int step_count = 4;
|
|
|
|
vec3 lightdir = u_light_direction.xyz;
|
|
vec3 eyedir = getWorldNormal(v_uv);
|
|
|
|
float alpha = dot(eyedir, lightdir);
|
|
|
|
float rayleigh_factor = phase(alpha, -0.01) * brightness.x;
|
|
float mie_factor = phase(alpha, mie_distribution) * brightness.y;
|
|
float spot = smoothstep(0.0, sun_size, phase(alpha, 0.9995)) * brightness.z;
|
|
|
|
vec3 eye_position = vec3(0.0, surface_height, 0.0);
|
|
float eye_depth = atmospheric_depth(eye_position, eyedir);
|
|
float step_length = eye_depth / float(step_count);
|
|
|
|
float eye_extinction = horizon_extinction(eye_position, eyedir, surface_height - 0.15);
|
|
|
|
vec3 rayleigh_collected = vec3(0.0, 0.0, 0.0);
|
|
vec3 mie_collected = vec3(0.0, 0.0, 0.0);
|
|
|
|
for (int i = 0; i < step_count; ++i) {
|
|
float sample_distance = step_length * float(i);
|
|
vec3 position = eye_position + eyedir * sample_distance;
|
|
float extinction = horizon_extinction(position, lightdir, surface_height - 0.35);
|
|
float sample_depth = atmospheric_depth(position, lightdir);
|
|
vec3 influx = absorb(sample_depth, vec3(intensity), strength.x) * extinction;
|
|
rayleigh_collected += absorb(sample_distance, air_color.rgb * influx, strength.y);
|
|
mie_collected += absorb(sample_distance, influx, strength.z);
|
|
}
|
|
|
|
rayleigh_collected = (rayleigh_collected * eye_extinction * pow(eye_depth, rayleigh_collection_power))/float(step_count);
|
|
mie_collected = (mie_collected * eye_extinction * pow(eye_depth, mie_collection_power))/float(step_count);
|
|
|
|
vec3 color = vec3(spot * mie_collected + mie_factor * mie_collected + rayleigh_factor * rayleigh_collected);
|
|
|
|
float fog_factor = getFogFactorSky(u_camera_world_pos.y, eyedir, u_fog_params.x, u_fog_params.y, u_fog_params.z);
|
|
o_color.xyz = mix(color.rgb, u_fog_color.rgb, fog_factor);
|
|
o_color.w = 1;
|
|
}
|
|
]] |