318 lines
No EOL
8.5 KiB
Text
318 lines
No EOL
8.5 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;
|
|
layout (binding=1) uniform sampler2D u_inscatter;
|
|
layout (binding=2) uniform sampler3D u_noise;
|
|
layout(std140, binding = 4) uniform Data {
|
|
vec4 u_cloud;
|
|
};
|
|
const float cloud_bot = 6000;
|
|
const float cloud_threshold = 0.2;
|
|
const float cloud_height = 3000;
|
|
|
|
float remap( float value, float inMin, float inMax, float outMin, float outMax )
|
|
{
|
|
float mappedValue = value;
|
|
|
|
if ( ( inMax - inMin ) == 0.0f )
|
|
{
|
|
mappedValue = ( outMax + outMin ) * 0.5f;
|
|
}
|
|
else
|
|
{
|
|
mappedValue = outMin + ( ( ( mappedValue - inMin ) / ( inMax - inMin ) ) * ( outMax - outMin ) );
|
|
}
|
|
|
|
return mappedValue;
|
|
}
|
|
|
|
#define UI0 1597334673U
|
|
#define UI1 3812015801U
|
|
#define UI2 uvec2(UI0, UI1)
|
|
#define UI3 uvec3(UI0, UI1, 2798796415U)
|
|
#define UIF (1.0 / float(0xffffffffU))
|
|
|
|
vec3 hash33(vec3 p)
|
|
{
|
|
uvec3 q = uvec3(ivec3(p)) * UI3;
|
|
q = (q.x ^ q.y ^ q.z)*UI3;
|
|
return -1. + 2. * vec3(q) * UIF;
|
|
}
|
|
|
|
float perlin(vec3 p)
|
|
{
|
|
vec3 pi = floor(p);
|
|
vec3 pf = p - pi;
|
|
|
|
vec3 w = pf * pf * (3.0 - 2.0 * pf);
|
|
|
|
return mix(
|
|
mix(
|
|
mix(dot(pf - vec3(0, 0, 0), hash33(pi + vec3(0, 0, 0))),
|
|
dot(pf - vec3(1, 0, 0), hash33(pi + vec3(1, 0, 0))),
|
|
w.x),
|
|
mix(dot(pf - vec3(0, 0, 1), hash33(pi + vec3(0, 0, 1))),
|
|
dot(pf - vec3(1, 0, 1), hash33(pi + vec3(1, 0, 1))),
|
|
w.x),
|
|
w.z),
|
|
mix(
|
|
mix(dot(pf - vec3(0, 1, 0), hash33(pi + vec3(0, 1, 0))),
|
|
dot(pf - vec3(1, 1, 0), hash33(pi + vec3(1, 1, 0))),
|
|
w.x),
|
|
mix(dot(pf - vec3(0, 1, 1), hash33(pi + vec3(0, 1, 1))),
|
|
dot(pf - vec3(1, 1, 1), hash33(pi + vec3(1, 1, 1))),
|
|
w.x),
|
|
w.z),
|
|
w.y);
|
|
}
|
|
|
|
float worley1(vec3 uv)
|
|
{
|
|
vec3 id = floor(uv);
|
|
vec3 p = fract(uv);
|
|
|
|
float minDist = 10000.;
|
|
for (float x = -1.; x <= 1.; ++x)
|
|
{
|
|
for(float y = -1.; y <= 1.; ++y)
|
|
{
|
|
for(float z = -1.; z <= 1.; ++z)
|
|
{
|
|
vec3 offset = vec3(x, y, z);
|
|
vec3 h = hash33(id + offset) * .5 + .5;
|
|
h += offset;
|
|
vec3 d = p - h;
|
|
minDist = min(minDist, dot(d, d));
|
|
}
|
|
}
|
|
}
|
|
|
|
// inverted worley noise
|
|
return 1. - minDist;
|
|
}
|
|
|
|
float worley(vec3 x) {
|
|
return saturate(worley1(x) * 0.625 + worley1(x * 2) * 0.25 + worley1(x * 4) * 0.125);
|
|
}
|
|
|
|
|
|
float gradientNoise(vec3 x, float freq)
|
|
{
|
|
// grid
|
|
vec3 p = floor(x);
|
|
vec3 w = fract(x);
|
|
|
|
// quintic interpolant
|
|
vec3 u = w * w * w * (w * (w * 6. - 15.) + 10.);
|
|
|
|
|
|
// gradients
|
|
vec3 ga = hash33(mod(p + vec3(0., 0., 0.), freq));
|
|
vec3 gb = hash33(mod(p + vec3(1., 0., 0.), freq));
|
|
vec3 gc = hash33(mod(p + vec3(0., 1., 0.), freq));
|
|
vec3 gd = hash33(mod(p + vec3(1., 1., 0.), freq));
|
|
vec3 ge = hash33(mod(p + vec3(0., 0., 1.), freq));
|
|
vec3 gf = hash33(mod(p + vec3(1., 0., 1.), freq));
|
|
vec3 gg = hash33(mod(p + vec3(0., 1., 1.), freq));
|
|
vec3 gh = hash33(mod(p + vec3(1., 1., 1.), freq));
|
|
|
|
// projections
|
|
float va = dot(ga, w - vec3(0., 0., 0.));
|
|
float vb = dot(gb, w - vec3(1., 0., 0.));
|
|
float vc = dot(gc, w - vec3(0., 1., 0.));
|
|
float vd = dot(gd, w - vec3(1., 1., 0.));
|
|
float ve = dot(ge, w - vec3(0., 0., 1.));
|
|
float vf = dot(gf, w - vec3(1., 0., 1.));
|
|
float vg = dot(gg, w - vec3(0., 1., 1.));
|
|
float vh = dot(gh, w - vec3(1., 1., 1.));
|
|
|
|
// interpolation
|
|
return va +
|
|
u.x * (vb - va) +
|
|
u.y * (vc - va) +
|
|
u.z * (ve - va) +
|
|
u.x * u.y * (va - vb - vc + vd) +
|
|
u.y * u.z * (va - vc - ve + vg) +
|
|
u.z * u.x * (va - vb - ve + vf) +
|
|
u.x * u.y * u.z * (-va + vb + vc - vd + ve - vf - vg + vh);
|
|
}
|
|
|
|
float perlinFbm(vec3 p, float freq, int octaves)
|
|
{
|
|
float G = exp2(-.85);
|
|
float amp = 1.;
|
|
float noise = 0.;
|
|
for (int i = 0; i < octaves; ++i)
|
|
{
|
|
noise += amp * gradientNoise(p * freq, freq);
|
|
freq *= 2.;
|
|
amp *= G;
|
|
}
|
|
|
|
return noise;
|
|
}
|
|
|
|
float miePhase(float g, float cos_theta)
|
|
{
|
|
float k = 1.55*g - 0.55*g*g*g;
|
|
float tmp = 1 + k * cos_theta;
|
|
return (1 - k * k) / (4 * M_PI * tmp * tmp);
|
|
}
|
|
|
|
float rayleighPhase(float cos_theta)
|
|
{
|
|
return 3 / (16.0 * M_PI) * (1 + cos_theta * cos_theta);
|
|
}
|
|
|
|
vec3 inscatter(vec2 uv, float linear_depth) {
|
|
const float sunlight = 3;
|
|
const vec3 u_scatter_mie = vec3(1 * 3.996 * 0.000001);
|
|
const vec3 u_scatter_rayleigh = vec3(5.802, 13.558, 33.1 ) * 10e-6;
|
|
|
|
const vec3 eyedir = getWorldNormal(uv);
|
|
const float cos_theta = dot(eyedir, Global.light_dir.xyz);
|
|
vec2 v = vec2(
|
|
saturate(linear_depth / 50e3),
|
|
max(0, eyedir.y)
|
|
);
|
|
vec4 insc = textureLod(u_inscatter, v, 0);
|
|
return
|
|
vec3(insc.a) * miePhase(0.75, -cos_theta) * sunlight * u_scatter_mie.rgb
|
|
+ insc.rgb * rayleighPhase(-cos_theta) * sunlight * u_scatter_rayleigh.rgb
|
|
;
|
|
}
|
|
|
|
float cloud(vec3 p) {
|
|
float cloud_top = cloud_bot + cloud_height;
|
|
if (p.y > cloud_top) return 0;
|
|
if (p.y < cloud_bot) return 0;
|
|
float height = saturate((p.y - cloud_bot) / cloud_height);
|
|
#if 0
|
|
|
|
p *= 1e-4;
|
|
vec3 ppp = p;
|
|
ppp.y *= u_cloud.z;
|
|
float pfbm = mix(1.0, perlinFbm(ppp * 0.3, 4, 7), 0.5);
|
|
pfbm = abs(pfbm * 2 - 1);
|
|
|
|
vec3 pp = p;
|
|
pp.y *= u_cloud.y;
|
|
float w = worley(pp);
|
|
float pw = remap(pfbm, 0.0, 1.0, w, 1.0); // perlin-worley
|
|
|
|
float cloud = remap(pw, w - 1.0, 1.0, 0.0, 1.0);
|
|
|
|
float cut = 0.79 * u_cloud.z;
|
|
//cut = cut + saturate(height - 0.9);
|
|
//cut = saturate(remap(height, 0, 0.1, 0, 1)) * saturate(remap(height, 0.5, 0.9, 1, 0)) * cut;
|
|
cloud = remap(cloud, cut, 1.0, 0.0, 1.0); // fake cloud coverage
|
|
|
|
|
|
return saturate(cloud) * 20;
|
|
#else
|
|
p *= 4e-5;
|
|
p.y *= 0.3;
|
|
vec4 shape = textureLod(u_noise, p * u_cloud.w, 0);
|
|
|
|
float lfn = remap(shape.y, shape.z, 1.0, 0.0, 1.0);
|
|
//lfn = remap(lfn, shape.w, 1.0, 0.0, 1.0);
|
|
|
|
float cloud = shape.x - shape.y * 0.2;
|
|
|
|
//cloud = remap(cloud, 1 - shape.y, 1, 0, 1);
|
|
//cloud = remap(cloud, 1 - shape.z, 1, 0, 1);
|
|
//cloud = remap(cloud, 1 - shape.w, 1, 0, 1);
|
|
//cloud = shape.x * 0.625 + shape.y * 0.25 + shape.z * 0.125;
|
|
|
|
vec4 hfn = textureLod(u_noise, p * 8, 0);
|
|
float hfn_fbm = hfn.y * 0.625 + hfn.z * 0.25 + hfn.w * 0.125;
|
|
float hfn_remapped = remap(cloud, -1+hfn_fbm, 1.0, 0.0, 1.0);
|
|
//float hfn_remapped = cloud * 0.85 + hfn_fbm * 0.15;
|
|
cloud = mix(cloud, hfn_remapped, 1);//saturate(height * 2));
|
|
cloud *= cloud;
|
|
//cloud = remap(cloud, -1 + lfn, 1, 0, 1);
|
|
return saturate(cloud - u_cloud.z - pow(height, 2)) * 15;
|
|
#endif
|
|
}
|
|
|
|
void main() {
|
|
#if 1
|
|
vec3 eyedir = getWorldNormal(v_uv);
|
|
float c = 0;
|
|
vec3 p = Global.camera_world_pos.xyz;
|
|
float transmittance = 1;
|
|
|
|
float cloud_top = cloud_bot + cloud_height;
|
|
|
|
if (p.y < cloud_bot && eyedir.y <= 0) discard;
|
|
if (p.y > cloud_top && eyedir.y >= 0) discard;
|
|
|
|
if (p.y < cloud_bot) {
|
|
p += eyedir * ((cloud_bot - p.y) / eyedir.y);
|
|
}
|
|
|
|
if(p.y > cloud_top) {
|
|
p += eyedir * ((p.y - cloud_top) / -eyedir.y);
|
|
|
|
}
|
|
|
|
p += eyedir * random(v_uv) * 100;
|
|
|
|
const uint STEP_COUNT = 40;
|
|
float step_len = min(1550, cloud_height / STEP_COUNT / abs(eyedir.y));
|
|
const float extinction = 7e-3;
|
|
float total_transmittance = 1;
|
|
for (int i = 0; i < STEP_COUNT; ++i) {
|
|
float dens = cloud(p);
|
|
if (dens > 0) {
|
|
step_len = 150;
|
|
}
|
|
else {
|
|
p += eyedir * step_len;
|
|
continue;
|
|
}
|
|
|
|
float opt_depth = dens * step_len;
|
|
|
|
float shadow_opt_depth = 0;
|
|
vec3 pshadow = p;
|
|
float shadow_step_len = 20;
|
|
for (int i = 0; i < 7; ++i) {
|
|
float dens = cloud(pshadow);
|
|
shadow_opt_depth += dens;
|
|
pshadow += Global.light_dir.xyz * shadow_step_len;
|
|
shadow_step_len *= 1.5;
|
|
}
|
|
float transmittance = exp(-opt_depth * extinction);
|
|
c += exp(-shadow_opt_depth * extinction * 20) * dens * total_transmittance;
|
|
total_transmittance *= transmittance;
|
|
|
|
p += eyedir * step_len;
|
|
if (total_transmittance < 0.001) break;
|
|
}
|
|
o_color.rgb = vec3(saturate(c)) + inscatter(v_uv, length(p - Global.camera_world_pos.xyz)) * (1 - total_transmittance);
|
|
//o_color.rgb = vec3(1);// + inscatter(v_uv, length(p));
|
|
float alpha = saturate(1 - total_transmittance);
|
|
o_color.a = alpha;
|
|
#else
|
|
vec4 noises = texture(u_noise, vec3(v_uv, u_cloud.x));
|
|
o_color.rgb = saturate(vec3((noises.x - u_cloud.y) / (1 - u_cloud.y)));
|
|
o_color.rgb = saturate(vec3((noises.y - u_cloud.y) / (1 - u_cloud.y)));
|
|
o_color.rgb*= o_color.rgb;
|
|
o_color.a = 1;
|
|
#endif
|
|
}
|
|
]] |