You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
342 lines
14 KiB
Plaintext
342 lines
14 KiB
Plaintext
|
9 months ago
|
shader_type spatial;
|
||
|
|
render_mode shadows_disabled;
|
||
|
|
|
||
|
|
#define CAUSTICS
|
||
|
|
#define FRESNEL
|
||
|
|
#define PLAYER_WAVES
|
||
|
|
#define DISPLACEMENT
|
||
|
|
#define SSR
|
||
|
|
|
||
|
|
group_uniforms color;
|
||
|
|
uniform vec3 absorption_color : source_color = vec3(1.0, 0.35, 0.0);
|
||
|
|
#ifdef FRESNEL
|
||
|
|
uniform float fresnel_radius : hint_range(0.0, 6.0, 0.01) = 2.0;
|
||
|
|
uniform vec3 fresnel_color : source_color = vec3(0.0, 0.57, 0.72);
|
||
|
|
#endif
|
||
|
|
uniform float roughness : hint_range(0.0, 1.0, 0.01) = 0.15;
|
||
|
|
uniform float specular : hint_range(0.0, 1.0, 0.01) = 0.25;
|
||
|
|
// Depth adjustment
|
||
|
|
uniform float depth_distance : hint_range(0.0, 50.0, 0.1) = 25.0;
|
||
|
|
uniform float beers_law : hint_range(0.0, 20.0, 0.1) = 4.5;
|
||
|
|
|
||
|
|
#ifdef DISPLACEMENT
|
||
|
|
group_uniforms displacement;
|
||
|
|
uniform float displacement_strength : hint_range(0.0, 5.0, 0.1) = 0.3;
|
||
|
|
uniform float displacement_scroll_speed : hint_range(0.0, 1.0, 0.001) = 0.1;
|
||
|
|
uniform vec2 displacement_scroll_offset = vec2 (-0.2, 0.3);
|
||
|
|
uniform float displacement_scale_offset = 0.5;
|
||
|
|
uniform vec2 displacement_scale = vec2(0.04);
|
||
|
|
uniform sampler2D displacement_texture : hint_default_black, repeat_enable;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
group_uniforms edge;
|
||
|
|
uniform float edge_thickness : hint_range(0.0, 1.0, 0.001) = 0.3;
|
||
|
|
uniform float edge_speed : hint_range(0.0, 1.0, 0.001) = 0.35;
|
||
|
|
uniform vec2 edge_noise_scale = vec2(0.4);
|
||
|
|
uniform sampler2D edge_noise : repeat_enable;
|
||
|
|
uniform sampler2D edge_ramp : repeat_disable;
|
||
|
|
|
||
|
|
#ifdef PLAYER_WAVES
|
||
|
|
group_uniforms player;
|
||
|
|
uniform float influence_size : hint_range(0.0, 4.0, 0.1) = 1.0;
|
||
|
|
uniform float player_wave_frequenzy : hint_range(0.0, 20.0, 0.1) = 10.0;
|
||
|
|
uniform float player_wave_speed : hint_range(0.0, 10.0, 0.1) = 5.0;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef CAUSTICS
|
||
|
|
group_uniforms caustics;
|
||
|
|
uniform float caustic_size : hint_range(0.0, 8.0, 0.01) = 2.0;
|
||
|
|
uniform float caustic_range : hint_range(0.0, 256.0, 0.1) = 40.0;
|
||
|
|
uniform float caustic_strength : hint_range(0.0, 1.0, 0.01) = 0.08;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef SSR
|
||
|
|
group_uniforms screen_space_reflections;
|
||
|
|
uniform float ssr_mix_strength : hint_range(0.0, 1.0, 0.01) = 0.65;
|
||
|
|
uniform float ssr_travel : hint_range(0.0, 300.0, 0.5) = 100.0;
|
||
|
|
uniform float ssr_resolution_near : hint_range(0.1, 10.0, 0.1) = 1.0;
|
||
|
|
uniform float ssr_resolution_far : hint_range(2.0, 20.0, 0.1) = 5.0;
|
||
|
|
uniform float ssr_tolerance : hint_range(0.0, 2.0, 0.01) = 1.0;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
group_uniforms normal_map;
|
||
|
|
uniform float refraction_strength : hint_range(0.0, 4.0, 0.01) = 1.25;
|
||
|
|
uniform float normal_map_strength : hint_range(0.0, 4.0, 0.01) = 1.0;
|
||
|
|
uniform float scroll_speed : hint_range(0.0, 1.0, 0.01) = 0.3;
|
||
|
|
uniform vec2 scroll_offset = vec2(0.1, -0.3);
|
||
|
|
uniform float scale_offset = 0.5;
|
||
|
|
uniform vec2 normal_map_scale = vec2(0.1);
|
||
|
|
uniform sampler2D normal_map : hint_normal, filter_linear_mipmap;
|
||
|
|
|
||
|
|
// Hidden Uniforms
|
||
|
|
uniform float wind_intensity; // Global shader parameter between 0.0 and 1.0
|
||
|
|
uniform vec3 wind_direction;
|
||
|
|
#ifdef PLAYER_WAVES
|
||
|
|
uniform vec3 player_position;
|
||
|
|
#endif
|
||
|
|
uniform sampler2D screen_texture: hint_screen_texture, filter_linear_mipmap, repeat_disable;
|
||
|
|
uniform sampler2D depth_texture: hint_depth_texture, filter_linear_mipmap, repeat_disable;
|
||
|
|
|
||
|
|
varying vec3 global_position;
|
||
|
|
|
||
|
|
#ifdef CAUSTICS
|
||
|
|
// Permutation polynomial hash credit Stefan Gustavson
|
||
|
|
vec4 permute(vec4 t) {
|
||
|
|
return t * (t * 34.0 + 133.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Gradient set is a normalized expanded rhombic dodecahedron
|
||
|
|
vec3 grad(float hash) {
|
||
|
|
|
||
|
|
// Random vertex of a cube, +/- 1 each
|
||
|
|
vec3 cube = mod(floor(hash / vec3(1.0, 2.0, 4.0)), 2.0) * 2.0 - 1.0;
|
||
|
|
|
||
|
|
// Random edge of the three edges connected to that vertex
|
||
|
|
// Also a cuboctahedral vertex
|
||
|
|
// And corresponds to the face of its dual, the rhombic dodecahedron
|
||
|
|
vec3 cuboct = cube;
|
||
|
|
cuboct[int(hash / 16.0)] = 0.0;
|
||
|
|
|
||
|
|
// In a funky way, pick one of the four points on the rhombic face
|
||
|
|
float type = mod(floor(hash / 8.0), 2.0);
|
||
|
|
vec3 rhomb = (1.0 - type) * cube + type * (cuboct + cross(cube, cuboct));
|
||
|
|
|
||
|
|
// Expand it so that the new edges are the same length
|
||
|
|
// as the existing ones
|
||
|
|
vec3 grad = fma(cuboct, vec3(1.22474487139), rhomb);
|
||
|
|
|
||
|
|
// To make all gradients the same length, we only need to shorten the
|
||
|
|
// second type of vector. We also put in the whole noise scale constant.
|
||
|
|
// The compiler should reduce it into the existing floats. I think.
|
||
|
|
grad *= fma(-0.042942436724648037, type, 1.0) * 3.5946317686139184;
|
||
|
|
|
||
|
|
return grad;
|
||
|
|
}
|
||
|
|
|
||
|
|
// BCC lattice split up into 2 cube lattices
|
||
|
|
vec4 os2NoiseWithDerivativesPart(vec3 X) {
|
||
|
|
vec3 b = floor(X);
|
||
|
|
vec4 i4 = vec4(X - b, 2.5);
|
||
|
|
|
||
|
|
// Pick between each pair of oppposite corners in the cube.
|
||
|
|
vec3 v1 = b + floor(dot(i4, vec4(.25)));
|
||
|
|
vec3 v2 = b + vec3(1, 0, 0) + vec3(-1, 1, 1) * floor(dot(i4, vec4(-.25, .25, .25, .35)));
|
||
|
|
vec3 v3 = b + vec3(0, 1, 0) + vec3(1, -1, 1) * floor(dot(i4, vec4(.25, -.25, .25, .35)));
|
||
|
|
vec3 v4 = b + vec3(0, 0, 1) + vec3(1, 1, -1) * floor(dot(i4, vec4(.25, .25, -.25, .35)));
|
||
|
|
|
||
|
|
// Gradient hashes for the four vertices in this half-lattice.
|
||
|
|
vec4 hashes = permute(mod(vec4(v1.x, v2.x, v3.x, v4.x), 289.0));
|
||
|
|
hashes = permute(mod(hashes + vec4(v1.y, v2.y, v3.y, v4.y), 289.0));
|
||
|
|
hashes = mod(permute(mod(hashes + vec4(v1.z, v2.z, v3.z, v4.z), 289.0)), 48.0);
|
||
|
|
|
||
|
|
// Gradient extrapolations & kernel function
|
||
|
|
vec3 d1 = X - v1; vec3 d2 = X - v2; vec3 d3 = X - v3; vec3 d4 = X - v4;
|
||
|
|
vec4 a = max(0.75 - vec4(dot(d1, d1), dot(d2, d2), dot(d3, d3), dot(d4, d4)), 0.0);
|
||
|
|
vec4 aa = a * a; vec4 aaaa = aa * aa;
|
||
|
|
vec3 g1 = grad(hashes.x); vec3 g2 = grad(hashes.y);
|
||
|
|
vec3 g3 = grad(hashes.z); vec3 g4 = grad(hashes.w);
|
||
|
|
vec4 extrapolations = vec4(dot(d1, g1), dot(d2, g2), dot(d3, g3), dot(d4, g4));
|
||
|
|
|
||
|
|
// Derivatives of the noise
|
||
|
|
vec4 derivative = -8.0 * mat4(vec4(d1,0.), vec4(d2,0.), vec4(d3,0.), vec4(d4,0.)) * (aa * a * extrapolations)
|
||
|
|
+ mat4(vec4(g1, 0.), vec4(g2, 0.), vec4(g3, 0.), vec4(g4, 0.)) * aaaa;
|
||
|
|
|
||
|
|
// Return it all as a vec4
|
||
|
|
return vec4(derivative.xyz, dot(aaaa, extrapolations));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Rotates domain, but preserve shape. Hides grid better in cardinal slices.
|
||
|
|
// Good for texturing 3D objects with lots of flat parts along cardinal planes.
|
||
|
|
vec4 os2NoiseWithDerivatives_Fallback(vec3 X) {
|
||
|
|
X = dot(X, vec3(2.0/3.0)) - X;
|
||
|
|
|
||
|
|
vec4 result = os2NoiseWithDerivativesPart(X) + os2NoiseWithDerivativesPart(X + 144.5);
|
||
|
|
|
||
|
|
return vec4(dot(result.xyz, vec3(2.0/3.0)) - result.xyz, result.w);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef FRESNEL
|
||
|
|
float fresnel(vec3 normal, vec3 view) {
|
||
|
|
return pow((1.0 - clamp(dot(normalize(normal), normalize(view)), 0.0, 1.0 )), fresnel_radius);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
|
||
|
|
vec2 refract_uv(inout vec2 uv, vec3 normal, float depth){
|
||
|
|
float strength1 = refraction_strength * depth;
|
||
|
|
uv += fma(strength1, length(normal), strength1 * -1.2);
|
||
|
|
return uv;
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef SSR
|
||
|
|
vec2 get_uv_from_view_position(vec3 position_view_space, mat4 proj_m)
|
||
|
|
{
|
||
|
|
vec4 position_clip_space = proj_m * vec4(position_view_space.xyz, 1.0);
|
||
|
|
vec2 position_ndc = position_clip_space.xy / position_clip_space.w;
|
||
|
|
return position_ndc.xy * 0.5 + 0.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
vec3 get_view_position_from_uv(vec2 uv, float depth, mat4 inv_proj_m)
|
||
|
|
{
|
||
|
|
vec4 position_ndc = vec4((uv * 2.0) - 1.0, depth, 1.0);
|
||
|
|
vec4 view_position = inv_proj_m * position_ndc;
|
||
|
|
return view_position.xyz /= view_position.w;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
bool in_bounds(vec2 uv) {
|
||
|
|
vec2 fruv = abs(floor(uv));
|
||
|
|
return fruv.x + fruv.y < 0.1;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void vertex() {
|
||
|
|
global_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||
|
|
|
||
|
|
#ifdef DISPLACEMENT
|
||
|
|
float time = TIME * displacement_scroll_speed * fma(wind_intensity, 0.7, 0.3);
|
||
|
|
float displace1 = texture(displacement_texture, fma(global_position.xz, displacement_scale, time * -wind_direction.xz)).r;
|
||
|
|
float displace2 = texture(displacement_texture, fma(global_position.xz, displacement_scale * displacement_scale_offset, time * (-wind_direction.xz + displacement_scroll_offset))).r;
|
||
|
|
float displacement_mixed = mix(displace1, displace2, 0.4);
|
||
|
|
float offset = fma(displacement_mixed, 2.0, -1.0) * displacement_strength;
|
||
|
|
VERTEX.y += offset;
|
||
|
|
global_position.y += offset;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void fragment() {
|
||
|
|
vec3 opposing_color = vec3(1.0) - absorption_color.rgb;
|
||
|
|
vec3 normalized_wind_direction = normalize(wind_direction);
|
||
|
|
float wind_intens_factor = fma(wind_intensity, 0.7, 0.3);
|
||
|
|
#ifdef FRESNEL
|
||
|
|
float fresnel_value = fresnel(NORMAL, VIEW);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
float time_factor = TIME * scroll_speed * wind_intens_factor;
|
||
|
|
vec3 n1 = textureLod(normal_map, fma(global_position.xz, normal_map_scale, time_factor * -normalized_wind_direction.xz), 2.0).xyz;
|
||
|
|
vec3 n2 = textureLod(normal_map, fma(global_position.xz, normal_map_scale * scale_offset, time_factor * 0.8 * (-normalized_wind_direction.xz + scroll_offset)), 2.0).xyz;
|
||
|
|
NORMAL_MAP = mix(n1, n2, 0.5);
|
||
|
|
NORMAL_MAP_DEPTH = normal_map_strength;
|
||
|
|
|
||
|
|
float depth_tex = texture(depth_texture, SCREEN_UV).r;
|
||
|
|
|
||
|
|
vec3 ndc = vec3(fma(SCREEN_UV, vec2(2.0), vec2(-1.0)), depth_tex);
|
||
|
|
vec4 world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
|
||
|
|
world.y /= world.w;
|
||
|
|
float vertey_y = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).y;
|
||
|
|
float relative_depth = vertey_y - world.y;
|
||
|
|
|
||
|
|
|
||
|
|
// Create Edge caused by other Objects
|
||
|
|
float edge_blend = clamp(relative_depth / -edge_thickness + 1.0, 0.0, 1.0);
|
||
|
|
vec2 edge_noise_uv = global_position.xz * edge_noise_scale * fma(normalized_wind_direction.xz, vec2(0.5), vec2(0.5));
|
||
|
|
edge_noise_uv = fma(-normalized_wind_direction.xz * TIME * edge_speed, vec2(wind_intens_factor), edge_noise_uv);
|
||
|
|
float edge_noise_sample = texture(edge_noise, edge_noise_uv).r;
|
||
|
|
float edge_mask = normalize( texture(edge_ramp, vec2(edge_noise_sample * fma(edge_blend, -1., 1.))).r);
|
||
|
|
|
||
|
|
// Create Ripples caused by player
|
||
|
|
float player_effect_mask = 0.0;
|
||
|
|
#ifdef PLAYER_WAVES
|
||
|
|
vec3 player_relative = vec3(global_position - player_position);
|
||
|
|
float player_height = smoothstep(1.0, 0.0, abs(player_relative.y));
|
||
|
|
float player_position_factor = smoothstep(influence_size, 0.0, length(player_relative.xz));
|
||
|
|
float player_waves = pow( fma( sin(fma(player_position_factor, player_wave_frequenzy, TIME * player_wave_speed)), 0.5, 0.5), 6.0);
|
||
|
|
float wave_distort = texture( edge_ramp, vec2( player_waves * (edge_noise_sample + 0.2) * player_position_factor * player_height)).x;
|
||
|
|
player_effect_mask = clamp(normalize( fma(wave_distort, -1.0, 0.4)), 0.0, 1.0);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
// combine Edge Mask with Player Ripples
|
||
|
|
float ripple_mask = clamp( fma( edge_mask, edge_blend, player_effect_mask), 0.0, 1.0);
|
||
|
|
|
||
|
|
// Calculate Fragment Depth
|
||
|
|
vec4 clip_pos = PROJECTION_MATRIX * vec4(VERTEX, 1.0);
|
||
|
|
clip_pos.xyz /= clip_pos.w;
|
||
|
|
DEPTH = clip_pos.z;
|
||
|
|
// Refract UV
|
||
|
|
vec2 refracted_uv = SCREEN_UV;
|
||
|
|
refract_uv(refracted_uv, NORMAL_MAP, sqrt(DEPTH) * relative_depth);
|
||
|
|
|
||
|
|
vec3 screen;
|
||
|
|
float depth_blend;
|
||
|
|
float refracted_depth_tex = texture(depth_texture, refracted_uv).x;
|
||
|
|
ndc = vec3(fma(refracted_uv, vec2(2.0), vec2(-1.0)), refracted_depth_tex);
|
||
|
|
world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
|
||
|
|
world.xyz /= world.w;
|
||
|
|
float depth_test = vertey_y - world.y;
|
||
|
|
|
||
|
|
// Caustic Effects
|
||
|
|
#ifdef CAUSTICS
|
||
|
|
float range_mod = clamp((VERTEX.z + caustic_range) * 0.05, 0.0, 1.0);
|
||
|
|
float caustic_value = 0.0;
|
||
|
|
// Protect yourself from calculating Noise at runtime with this handy if statement!
|
||
|
|
if (range_mod > 0.0) {
|
||
|
|
vec3 X = vec3(world.xz * caustic_size, mod(TIME, 578.0) * 0.8660254037844386);
|
||
|
|
vec4 noiseResult = os2NoiseWithDerivatives_Fallback(X);
|
||
|
|
noiseResult = os2NoiseWithDerivatives_Fallback(X - noiseResult.xyz / 16.0);
|
||
|
|
caustic_value = fma(noiseResult.w, 0.5, 0.5) * range_mod * range_mod;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/*
|
||
|
|
Sometimes the Water Refraction would cause the sampling of a screen position that is either
|
||
|
|
outside the screen bounds or where another object is infront of the water.
|
||
|
|
Switching back to the unrefracted SCREEN_UV fixes that.
|
||
|
|
*/
|
||
|
|
|
||
|
|
if (depth_test > -0.0001 && in_bounds(refracted_uv)) {
|
||
|
|
screen = texture(screen_texture, refracted_uv).rgb * 0.9;
|
||
|
|
depth_blend = clamp(depth_test / depth_distance, 0.0, 1.0);
|
||
|
|
depth_blend = fma(exp(-depth_blend * beers_law), -1.0, 1.0);
|
||
|
|
} else {
|
||
|
|
screen = texture(screen_texture, SCREEN_UV).rgb * 0.9;
|
||
|
|
depth_blend = clamp(relative_depth / depth_distance, 0.0, 1.0);
|
||
|
|
depth_blend = fma(exp(-depth_blend * beers_law), -1.0, 1.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef SSR
|
||
|
|
vec3 view_normal_map = mat3(VIEW_MATRIX) * (vec3(NORMAL_MAP.x, 0.0, NORMAL_MAP.y) * 2.0 - 1.0);
|
||
|
|
vec3 combined_normal = normalize(view_normal_map * (NORMAL_MAP_DEPTH * 0.15) + NORMAL);
|
||
|
|
vec3 reflacted_path = reflect(-VIEW, combined_normal);
|
||
|
|
|
||
|
|
vec2 current_screen_pos = vec2(0.0);
|
||
|
|
vec3 current_view_pos = VERTEX;
|
||
|
|
vec3 sampled_color = vec3(-1.0);
|
||
|
|
float current_stepD = 0.0;
|
||
|
|
float current_depth = 0.0;
|
||
|
|
float alpha_hit = 0.0;
|
||
|
|
for(float i = 0.01; i < ssr_travel; i++) {
|
||
|
|
current_stepD = mix(ssr_resolution_near, ssr_resolution_far,float(i) / float(ssr_travel));
|
||
|
|
current_view_pos += reflacted_path * current_stepD;
|
||
|
|
current_screen_pos = get_uv_from_view_position(current_view_pos, PROJECTION_MATRIX);
|
||
|
|
if (!in_bounds(current_screen_pos)) {break;}
|
||
|
|
current_depth = get_view_position_from_uv(current_screen_pos, texture(depth_texture, current_screen_pos).x, INV_PROJECTION_MATRIX).z - current_view_pos.z;
|
||
|
|
|
||
|
|
if (current_depth > -0.0001 && current_depth <= ssr_tolerance * current_stepD) {
|
||
|
|
sampled_color = textureLod(screen_texture, current_screen_pos, 0.5).rgb;
|
||
|
|
vec2 ruv = 1.0 - abs(current_screen_pos * 2.0 - 1.0);
|
||
|
|
ruv = pow(ruv, vec2(0.5));
|
||
|
|
alpha_hit = clamp(min(ruv.x, ruv.y), 0.0, 1.0);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
i += current_stepD;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
vec3 color = clamp(screen - absorption_color.rgb * depth_blend, vec3(0.0), vec3(1.0)); // Absorb Screen Color
|
||
|
|
color = mix(color, opposing_color, depth_blend*depth_blend); // Apply depth color
|
||
|
|
#ifdef FRESNEL
|
||
|
|
color = mix(color, fresnel_color, fresnel_value); // Apply fresnel color
|
||
|
|
#endif
|
||
|
|
#ifdef CAUSTICS
|
||
|
|
color = clamp(color + caustic_value * caustic_strength * (1.0 - depth_blend), vec3(0.0), vec3(1.0));
|
||
|
|
#endif
|
||
|
|
#ifdef SSR
|
||
|
|
color = mix(color, sampled_color, alpha_hit * (1.0 - roughness) * ssr_mix_strength);
|
||
|
|
#endif
|
||
|
|
color = mix(color, vec3(0.98), ripple_mask); // Apply Ripples
|
||
|
|
ALBEDO = color;
|
||
|
|
ROUGHNESS = roughness;
|
||
|
|
SPECULAR = specular;
|
||
|
|
}
|