how do i add realtime planar reflections to my water shader ?
shader_type spatial;
render_mode cull_disabled;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, repeat_disable;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, repeat_disable;
uniform float refraction : hint_range(0.0, 0.1) = 0.02;
// Natural water color properties
uniform vec3 shallow_color : source_color = vec3(0.325, 0.807, 0.971);
uniform vec3 deep_color : source_color = vec3(0.086, 0.407, 0.560);
uniform float water_clarity : hint_range(0.1, 10.0) = 1.5;
// Enhanced wave system
uniform float wave_scale = 8.0;
uniform float wave_scale_detail = 3.0;
uniform float normal_strength : hint_range(0.0, 3.0) = 1.2;
uniform float detail_strength : hint_range(0.0, 1.0) = 0.3;
// Two wave layers for natural movement
uniform sampler2D normal1 : hint_normal,repeat_enable,filter_linear_mipmap;
uniform vec2 wave_dir1 = vec2(0.8, 0.6);
uniform sampler2D normal2 : hint_normal,repeat_enable,filter_linear_mipmap;
uniform vec2 wave_dir2 = vec2(-0.4, 0.7);
uniform float wave_speed : hint_range(0.0, 0.2) = 0.04;
uniform float wave_speed_detail : hint_range(0.0, 0.5) = 0.15;
// Enhanced foam system
uniform float foam_amount : hint_range(0.0, 3.0) = 1.2;
uniform float foam_cutoff : hint_range(0.0, 1.0) = 0.166;
uniform float foam_fade : hint_range(0.0, 2.0) = 0.8;
uniform vec3 foam_tint : source_color = vec3(0.95, 0.98, 1.0);
uniform sampler2D foam_texture : hint_default_white,repeat_enable,filter_linear_mipmap;
uniform float foam_scale : hint_range(1.0, 20.0) = 10.0;
// Surface properties
uniform float roughness_min : hint_range(0.0, 0.5) = 0.02;
uniform float roughness_max : hint_range(0.0, 1.0) = 0.15;
// Underwater effect
uniform vec4 under_color: source_color = vec4(0.4, 0.5, 0.3, 0.8);
uniform float distortion_falloff : hint_range(0.0, 5.0) = 2.0;
uniform float refraction_edge_fade : hint_range(0.0, 0.5) = 0.15;
// All varying variables removed - using built-in variables instead
// Improved noise function for more natural patterns
float noise(vec2 uv) {
return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
}
float smooth_noise(vec2 uv) {
vec2 i = floor(uv);
vec2 f = fract(uv);
f = f * f * (3.0 - 2.0 * f);
float a = noise(i);
float b = noise(i + vec2(1.0, 0.0));
float c = noise(i + vec2(0.0, 1.0));
float d = noise(i + vec2(1.0, 1.0));
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
}
void vertex() {
// All calculations moved to fragment shader using built-in variables
}
void fragment() {
// Calculate world position in fragment shader
vec3 world_position = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
// Enhanced two-layer wave normal calculation
float time_offset = TIME * wave_speed;
float time_detail = TIME * wave_speed_detail;
vec2 wave_uv = world_position.xz / wave_scale;
vec2 wave_uv_detail = world_position.xz / wave_scale_detail;
// Primary wave layers
vec3 normal_sample1 = texture(normal1, wave_uv + wave_dir1 * time_offset).rgb;
vec3 normal_sample2 = texture(normal2, wave_uv + wave_dir2 * time_offset * 0.8).rgb;
// Detail layer for small ripples
vec3 detail_normal = texture(normal1, wave_uv_detail + wave_dir1 * time_detail).rgb;
// Blend primary normals
vec3 normal_blend = mix(normal_sample1, normal_sample2, 0.5);
// Add detail layer
normal_blend = mix(normal_blend, detail_normal, detail_strength);
// Convert to world space normal
vec3 world_normal = (normal_blend * 2.0 - 1.0);
world_normal.xy *= normal_strength;
world_normal = normalize(TANGENT * world_normal.x + BINORMAL * world_normal.y + NORMAL * world_normal.z);
// Depth calculations
float depth_raw = texture(DEPTH_TEXTURE, SCREEN_UV).r;
vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth_raw);
vec4 world_pos = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
float depth_texture_y = world_pos.y / world_pos.w;
float vertex_y = world_position.y;
float water_depth = max(0.0, vertex_y - depth_texture_y);
// Natural water color mixing based on depth
float depth_factor = 1.0 - exp(-water_depth * water_clarity);
vec3 water_color = mix(shallow_color, deep_color, depth_factor);
// Improved refraction with natural distortion
float refraction_strength = refraction * clamp(water_depth * distortion_falloff, 0.0, 1.0);
vec2 distortion = world_normal.xy * refraction_strength;
vec2 distorted_uv = SCREEN_UV + distortion;
// Smooth edge handling for refraction
vec2 edge_distance = min(distorted_uv, 1.0 - distorted_uv);
float edge_fade = smoothstep(0.0, refraction_edge_fade, min(edge_distance.x, edge_distance.y));
distorted_uv = mix(SCREEN_UV, distorted_uv, edge_fade);
distorted_uv = clamp(distorted_uv, vec2(0.0), vec2(1.0));
vec3 refracted_color = texture(SCREEN_TEXTURE, distorted_uv).rgb;
// Enhanced foam calculation
float foam_depth_factor = 1.0 - smoothstep(0.0, foam_amount, water_depth);
vec2 foam_uv_base = world_position.xz / foam_scale;
vec2 foam_uv1 = foam_uv_base + wave_dir1 * time_offset * 0.15;
vec2 foam_uv2 = foam_uv_base + wave_dir2 * time_offset * 0.08;
vec3 foam_sample1 = texture(foam_texture, foam_uv1).rgb;
vec3 foam_sample2 = texture(foam_texture, foam_uv2 * 1.3).rgb;
vec3 foam_sample = mix(foam_sample1, foam_sample2, 0.4);
float foam_noise1 = smooth_noise(wave_uv + wave_dir1 * time_offset * 0.05);
float foam_noise2 = smooth_noise(wave_uv_detail + wave_dir2 * time_detail * 0.03);
float foam_noise = mix(foam_noise1, foam_noise2, 0.6);
float foam_wave_factor = (normal_blend.r + normal_blend.g) * 0.5;
float foam_mask = foam_depth_factor * (foam_noise + foam_wave_factor * 0.5);
foam_mask = smoothstep(foam_cutoff, foam_cutoff + foam_fade, foam_mask);
vec3 foam_final = foam_sample * foam_tint * foam_mask;
// Water transparency and color blending
float water_alpha = 1.0 - exp(-water_depth * water_clarity * 0.5);
// Start with refracted background
vec3 final_color = refracted_color;
// Blend in water color based on depth
final_color = mix(final_color, water_color, water_alpha * 0.6);
// Add foam
final_color = mix(final_color, foam_final, foam_mask);
// Dynamic roughness based on wave intensity
float wave_intensity = length(world_normal.xy);
float surface_roughness = mix(roughness_min, roughness_max, wave_intensity);
// Final output
ALBEDO = mix(under_color.rgb, final_color, float(FRONT_FACING));
ROUGHNESS = surface_roughness;
SPECULAR = 0.5;
NORMAL_MAP = normal_blend;
ALPHA = mix(under_color.a, water_alpha, float(FRONT_FACING));
}
'''