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