Substantially faster water shaders

This commit is contained in:
Joshua Barretto 2022-09-24 12:33:26 +01:00
parent 30de7b4fb8
commit ce7dda3e2f
4 changed files with 95 additions and 55 deletions

View File

@ -53,71 +53,69 @@ layout(location = 0) out vec4 tgt_color;
#include <light.glsl>
#include <lod.glsl>
vec2 wavedx(vec2 position, vec2 direction, float speed, float frequency, float timeshift) {
float x = dot(direction, position) * frequency + timeshift * speed;
float wave = pow(sin(x) + 0.5, 2);
float dx = wave * cos(x);
return vec2(wave, -dx);
void wave_dx(vec4 posx, vec4 posy, vec2 dir, float speed, float frequency, float timeshift, out vec4 wave, out vec4 dx) {
vec4 x = vec4(
dot(dir, vec2(posx.x, posy.x)),
dot(dir, vec2(posx.y, posy.y)),
dot(dir, vec2(posx.z, posy.z)),
dot(dir, vec2(posx.w, posy.w))
) * frequency + timeshift * speed;
wave = sin(x) + 0.5;
wave *= wave;
dx = -wave * cos(x);
}
// Based on https://www.shadertoy.com/view/MdXyzX
float wave_height(vec2 pos){
// Based loosely on https://www.shadertoy.com/view/MdXyzX.
// Modified to allow calculating the wave function 4 times at once using different positions (used for intepolation
// for moving water). The general idea is to sample the wave function at different positions, where those positions
// depend on increments of the velocity, and then interpolate between those velocities to get a smooth water velocity.
vec4 wave_height(vec4 posx, vec4 posy) {
float iter = 0.0;
float phase = 4.0;
float weight = 1.5;
float w = 0.0;
vec4 w = vec4(0.0);
float ws = 0.0;
const float speed_per_iter = 0.1;
#if (FLUID_MODE == FLUID_MODE_HIGH)
float speed = 1.0;
pos *= 0.15;
posx *= 0.2;
posy *= 0.2;
const float drag_factor = 0.03;
const float iters = 21;
#else
float speed = 2.0;
pos *= 0.3;
posx *= 0.3;
posy *= 0.3;
const float drag_factor = 0.04;
const float iters = 11;
#endif
const float iter_shift = (3.14159 * 2.0) / 7.3;
vec2 dir = vec2(
sin(pos.y * 0.1),
sin(pos.x * 0.1)
) * 0;
for(int i = 0; i < iters; i ++) {
vec2 p = vec2(sin(iter), cos(iter));
vec2 res = wavedx(pos, p, speed, phase, tick.x);
pos += p * res.y * weight * drag_factor;
w += res.x * weight * (1.0 + max(dot(p, -dir), 0.0));
vec4 wave, dx;
wave_dx(posx, posy, p, speed, phase, tick.x, wave, dx);
posx += p.x * dx * weight * drag_factor;
posy += p.y * dx * weight * drag_factor;
w += wave * weight;
iter += iter_shift * 1.5;
ws += weight;
weight = mix(weight, 0.0, 0.2);
phase *= 1.23;
phase *= 1.2;
speed += speed_per_iter;
}
return w / ws * 10.0;
return w / ws * 20.0;
}
float wave_height2(vec2 pos){
vec2 vel = vec2(sin(pos.x * 0.2), cos(pos.y * 0.2)) * 2.0;
vel = cross(vec3(vel, 0), vec3(0, 0, 1)).xy;
vel = lod_norm(f_pos.xy - 16).xy * 10.0;
vel = f_vel * 2.5;
float hx = mix(
wave_height(pos - vec2(1, 0) * tick.x * floor(vel.x) - vec2(0, 1) * tick.x * floor(vel.y)),
wave_height(pos - vec2(1, 0) * tick.x * floor(vel.x + 1.0) - vec2(0, 1) * tick.x * floor(vel.y)),
fract(vel.x + 1.0)
);
float hx2 = mix(
wave_height(pos - vec2(1, 0) * tick.x * floor(vel.x) - vec2(0, 1) * tick.x * floor(vel.y + 1.0)),
wave_height(pos - vec2(1, 0) * tick.x * floor(vel.x + 1.0) - vec2(0, 1) * tick.x * floor(vel.y + 1.0)),
fract(vel.x + 1.0)
vec4 heights = wave_height(
pos.x - tick.x * floor(f_vel.x) - vec2(0.0, tick.x).xyxy,
pos.y - tick.x * floor(f_vel.y) - vec2(0.0, tick.x).xxyy
);
return mix(
hx,
hx2,
fract(vel.y + 1.0)
mix(heights.x, heights.y, fract(f_vel.x + 1.0)),
mix(heights.z, heights.w, fract(f_vel.x + 1.0)),
fract(f_vel.y + 1.0)
);
}
@ -247,14 +245,6 @@ void main() {
// TODO: Make this more efficient?
ray_dir = normalize(max(reflect_ray_dir, vec3(-1.0, -1.0, 0.0)));
}
vec3 reflect_color = get_sky_color(/*reflect_ray_dir*/ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.125, true);
reflect_color = get_cloud_color(reflect_color, ray_dir, f_pos.xyz, time_of_day.x, 100000.0, 0.1);
reflect_color *= f_light;
// Prevent the sky affecting light when underground
float not_underground = clamp((f_pos.z - f_alt) / 32.0 + 1.0, 0.0, 1.0);
reflect_color *= not_underground;
// /*const */vec3 water_color = srgb_to_linear(vec3(0.2, 0.5, 1.0));
// /*const */vec3 water_color = srgb_to_linear(vec3(0.8, 0.9, 1.0));
// NOTE: Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths.
@ -275,6 +265,21 @@ void main() {
// float moon_shade_frac = horizon_at(/*f_shadow, f_pos.z, */f_pos, moon_dir);
// float shade_frac = /*1.0;*/sun_shade_frac + moon_shade_frac;
vec3 reflect_color;
#if (FLUID_MODE == FLUID_MODE_HIGH)
reflect_color = get_sky_color(ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.125, sun_shade_frac > 0.5);
reflect_color = get_cloud_color(reflect_color, ray_dir, f_pos.xyz, time_of_day.x, 100000.0, 0.1);
#else
reflect_color = get_sky_color(ray_dir, time_of_day.x, f_pos, vec3(-100000), 0.125, sun_shade_frac > 0.5, 1.0, true);
#endif
// Sort of non-physical, but we try to balance the reflection intensity with the direct light from the sun,
// resulting in decent reflection of the ambient environment even after the sun has gone down.
reflect_color *= f_light * (sun_shade_frac * 0.75 + 0.25);
// Prevent the sky affecting light when underground
float not_underground = clamp((f_pos.z - f_alt) / 32.0 + 1.0, 0.0, 1.0);
reflect_color *= not_underground;
// DirectionalLight sun_info = get_sun_info(sun_dir, sun_shade_frac, light_pos);
float point_shadow = shadow_at(f_pos, f_norm);
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, /*sun_pos*/f_pos);
@ -370,7 +375,7 @@ void main() {
// diffuse_light += point_light;
// reflected_light += point_light;
// vec3 surf_color = srgb_to_linear(vec3(0.2, 0.5, 1.0)) * light * diffuse_light * ambient_light;
const float REFLECTANCE = 0.5;
const float REFLECTANCE = 1.0;
vec3 surf_color = illuminate(max_light, view_dir, water_color * emitted_light/* * log(1.0 - MU_WATER)*/, /*cam_attenuation * *//*water_color * */reflect_color * REFLECTANCE + water_color * reflected_light/* * log(1.0 - MU_WATER)*/);
// passthrough = pow(passthrough, 1.0 / (1.0 + water_depth_to_camera));

View File

@ -1,8 +1,14 @@
#include <lod.glsl>
#include <sky.glsl>
vec3 get_cloud_color(vec3 surf_color, vec3 dir, vec3 origin, float time_of_day, float max_dist, float quality) {
// Underwater light attenuation
surf_color = water_diffuse(surf_color, dir, max_dist);
if (max_dist < DIST_CAP) {
vec3 sky_light = get_sky_light(dir, time_of_day, false);
surf_color = mix(sky_light, surf_color, 1.0 / exp(max_dist / 5000.0));
}
return surf_color;
}

View File

@ -26,7 +26,7 @@ const vec3 DAWN_LIGHT = vec3(5.0, 2.0, 1.15);
const vec3 SUN_HALO_DAWN = vec3(8.2, 3.0, 2.1);
const vec3 SKY_DAY_TOP = vec3(0.1, 0.5, 0.9);
const vec3 SKY_DAY_MID = vec3(0.02, 0.28, 0.8);
const vec3 SKY_DAY_MID = vec3(0.18, 0.28, 0.6);
const vec3 SKY_DAY_BOT = vec3(0.1, 0.2, 0.3);
const vec3 DAY_LIGHT = vec3(3.8, 3.0, 1.8);
const vec3 SUN_HALO_DAY = vec3(0.25, 0.25, 0.001);
@ -570,7 +570,7 @@ vec3 get_sky_light(vec3 dir, float time_of_day, bool with_stars) {
return sky_color * magnetosphere_tint;
}
vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_features, float refractionIndex) {
vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_features, float refractionIndex, bool fake_clouds) {
// Sky color
/* vec3 sun_dir = get_sun_dir(time_of_day);
vec3 moon_dir = get_moon_dir(time_of_day); */
@ -591,9 +591,13 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q
float sun_halo_power = 20.0;
#if (CLOUD_MODE == CLOUD_MODE_NONE)
sun_halo_power = 1000.0;
sun_halo_color *= 0.1;
if (true) {
#else
if (fake_clouds || medium.x == MEDIUM_WATER) {
#endif
sun_halo_power = 50.0;
sun_halo_color *= 0.025;
}
vec3 sun_halo = sun_halo_color * 25 * pow(max(dot(dir, -sun_dir), 0), sun_halo_power);
vec3 sun_surf = vec3(0);
@ -601,6 +605,13 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q
float angle = 0.00035;
sun_surf = clamp((dot(dir, -sun_dir) - (1.0 - angle)) * 4 / angle, 0, 1) * SUN_SURF_COLOR * SUN_COLOR_FACTOR;
}
#if (CLOUD_MODE == CLOUD_MODE_NONE)
if (true) {
#else
if (fake_clouds || medium.x == MEDIUM_WATER) {
#endif
sun_surf *= 0.1;
}
vec3 sun_light = sun_halo + sun_surf;
// Moon
@ -611,9 +622,13 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q
float moon_halo_power = 20.0;
#if (CLOUD_MODE == CLOUD_MODE_NONE)
if (true) {
#else
if (fake_clouds || medium.x == MEDIUM_WATER) {
#endif
moon_halo_power = 2500.0;
moon_halo_color *= 0.1;
#endif
}
vec3 moon_halo = moon_halo_color * pow(max(dot(dir, -moon_dir), 0), moon_halo_power);
vec3 moon_surf = vec3(0);
@ -625,10 +640,14 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q
// Replaced all clamp(sun_dir, 0, 1) with max(sun_dir, 0) because sun_dir is calculated from sin and cos, which are never > 1
vec3 sky_color;
#if (CLOUD_MODE == CLOUD_MODE_NONE)
vec3 sky_color = get_sky_light(dir, time_of_day, true);
if (true) {
#else
vec3 sky_color;
if (fake_clouds || medium.x == MEDIUM_WATER) {
#endif
sky_color = get_sky_light(dir, time_of_day, false);
} else {
if (medium.x == MEDIUM_WATER) {
sky_color = get_sky_light(dir, time_of_day, true);
} else {
@ -636,13 +655,17 @@ vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float q
float star = is_star_at(star_dir);
sky_color = vec3(0) + star;
}
#endif
}
return sky_color + sun_light + moon_light;
}
vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_features, float refractionIndex) {
return get_sky_color(dir, time_of_day, origin, f_pos, quality, with_features, refractionIndex, false);
}
vec3 get_sky_color(vec3 dir, float time_of_day, vec3 origin, vec3 f_pos, float quality, bool with_stars) {
return get_sky_color(dir, time_of_day, origin, f_pos, quality, with_stars, 1.0);
return get_sky_color(dir, time_of_day, origin, f_pos, quality, with_stars, 1.0, false);
}
float fog(vec3 f_pos, vec3 focus_pos, uint medium) {

View File

@ -656,8 +656,14 @@ void main() {
float passthrough = dot(faceforward(f_norm, f_norm, cam_to_frag), -cam_to_frag);
vec3 reflect_color = get_sky_color(reflect_ray, time_of_day.x, f_pos, vec3(-100000), 0.125, true);
reflect_color = get_cloud_color(reflect_color, reflect_ray, cam_pos.xyz, time_of_day.x, 100000.0, 0.1);
vec3 reflect_color;
#if (FLUID_MODE == FLUID_MODE_HIGH)
reflect_color = get_sky_color(reflect_ray, time_of_day.x, f_pos, vec3(-100000), 0.125, sun_shade_frac > 0.5);
reflect_color = get_cloud_color(reflect_color, reflect_ray, cam_pos.xyz, time_of_day.x, 100000.0, 0.1);
#else
reflect_color = get_sky_color(reflect_ray, time_of_day.x, f_pos, vec3(-100000), 0.125, sun_shade_frac > 0.5, 1.0, true);
#endif
reflect_color *= sun_shade_frac * 0.75 + 0.25;
const float REFLECTANCE = 0.5;
surf_color = illuminate(max_light, view_dir, f_col * emitted_light, reflect_color * REFLECTANCE + water_color * reflected_light);