LumixEngine/data/pipelines/sky.shd
2019-10-14 22:28:06 +02:00

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;
}
]]