Variable waterFragmentShaderConst
waterFragmentShader: "\n uniform float time;\n varying vec2 vUv;\n varying vec3 vWorldPos;\n varying vec3 vNormal;\n varying vec3 vViewDir;\n \n // Procedural noise for water detail\n float hash(vec2 p) {\n return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);\n }\n \n float noise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n \n float a = hash(i);\n float b = hash(i + vec2(1.0, 0.0));\n float c = hash(i + vec2(0.0, 1.0));\n float d = hash(i + vec2(1.0, 1.0));\n \n return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);\n }\n \n // Fresnel effect for realistic water reflections\n float fresnel(vec3 viewDir, vec3 normal, float power) {\n return pow(1.0 - max(dot(viewDir, normal), 0.0), power);\n }\n \n // Procedural normal map simulation\n vec3 proceduralNormal(vec2 uv, float time) {\n // Two layers of scrolling noise for normal perturbation\n vec2 uv1 = uv * 4.0 + vec2(time * 0.05, time * 0.03);\n vec2 uv2 = uv * 3.0 - vec2(time * 0.04, time * 0.06);\n \n float n1 = noise(uv1);\n float n2 = noise(uv2);\n \n // Create normal perturbation\n vec3 normalOffset = vec3(\n (n1 - 0.5) * 0.3,\n 1.0,\n (n2 - 0.5) * 0.3\n );\n \n return normalize(normalOffset);\n }\n \n void main() {\n // Base water colors\n vec3 deepColor = vec3(0.02, 0.1, 0.15);\n vec3 shallowColor = vec3(0.1, 0.3, 0.4);\n vec3 foamColor = vec3(0.8, 0.9, 0.95);\n vec3 reflectionColor = vec3(0.6, 0.7, 0.8);\n \n // Animated UV scrolling for detail\n vec2 scrollUV1 = vWorldPos.xz * 0.5 + vec2(time * 0.02, time * 0.015);\n vec2 scrollUV2 = vWorldPos.xz * 0.3 - vec2(time * 0.015, time * 0.025);\n \n // Multi-layered ripple pattern with UV scrolling\n float ripple1 = sin(scrollUV1.x * 4.0) * cos(scrollUV1.y * 3.0);\n float ripple2 = sin(scrollUV2.x * 5.0) * cos(scrollUV2.y * 4.0);\n float ripple = (ripple1 + ripple2) * 0.25 + 0.5;\n \n // Procedural normal map for surface detail\n vec3 detailNormal = proceduralNormal(vWorldPos.xz * 0.2, time);\n vec3 finalNormal = normalize(vNormal + detailNormal * 0.3);\n \n // Depth gradient based on distance from center\n float depth = length(vWorldPos.xz) / 50.0;\n depth = clamp(depth, 0.0, 1.0);\n \n // Fresnel effect for reflections\n float fresnelFactor = fresnel(vViewDir, finalNormal, 3.0);\n \n // Mix colors based on depth\n vec3 col = mix(shallowColor, deepColor, depth);\n \n // Add ripple highlights\n col += ripple * 0.08;\n \n // Add fresnel reflections\n col = mix(col, reflectionColor, fresnelFactor * 0.4);\n \n // Foam at edges (shallow water) with animated detail\n float foamNoise = noise(vWorldPos.xz * 2.0 + time * 0.5);\n float foam = smoothstep(0.8, 1.0, 1.0 - depth) * ripple * foamNoise;\n col = mix(col, foamColor, foam * 0.4);\n \n // Specular highlights from normal\n vec3 lightDir = normalize(vec3(1.0, 1.0, 0.5));\n float specular = pow(max(dot(reflect(-lightDir, finalNormal), vViewDir), 0.0), 32.0);\n col += specular * 0.3;\n \n // Transparency based on depth and fresnel\n float alpha = mix(0.6, 0.9, depth) * (1.0 - fresnelFactor * 0.2);\n \n gl_FragColor = vec4(col, alpha);\n }\n" = ...