From 3cfe5c0b37d68d3a907a3864fda30abb1acb4a57 Mon Sep 17 00:00:00 2001 From: Gulum Date: Sat, 31 Jan 2026 23:55:56 +0100 Subject: [PATCH] Add Simplex noise functions and integrate noise-based displacement for enhanced wave detail --- index.html | 129 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 97 insertions(+), 32 deletions(-) diff --git a/index.html b/index.html index 59c5fd6..8744547 100644 --- a/index.html +++ b/index.html @@ -392,6 +392,73 @@ varying float v_foamFactor; varying float v_distanceFade; + // ============ Simplex Noise Functions ============ + // Permutation polynomial: (34x^2 + x) mod 289 + vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); } + + // 2D Simplex noise + float snoise(vec2 v) { + const vec4 C = vec4(0.211324865405187, 0.366025403784439, + -0.577350269189626, 0.024390243902439); + vec2 i = floor(v + dot(v, C.yy)); + vec2 x0 = v - i + dot(i, C.xx); + vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + i = mod(i, 289.0); + vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0)); + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m; m = m*m; + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h); + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); + } + + // Fractal Brownian Motion (FBM) using simplex noise + float fbm(vec2 p, float time, int octaves, float lacunarity, float gain) { + float sum = 0.0; + float amp = 1.0; + float freq = 1.0; + float maxAmp = 0.0; + + for (int i = 0; i < 6; i++) { + if (i >= octaves) break; + // Add subtle animation + vec2 animatedP = p * freq + vec2(time * 0.5 * float(i + 1), time * 0.3); + sum += snoise(animatedP) * amp; + maxAmp += amp; + amp *= gain; + freq *= lacunarity; + } + + return sum / maxAmp; + } + + // Get noise-based displacement and normal contribution + vec3 noiseWave(vec2 pos, float time, float scale, float amplitude, out vec3 normalContrib) { + vec2 p = pos * scale; + + // Sample noise at offset positions for gradient/normal calculation + float eps = 0.1; + float h = fbm(p, time, 4, 2.0, 0.5) * amplitude; + float hx = fbm(p + vec2(eps, 0.0), time, 4, 2.0, 0.5) * amplitude; + float hy = fbm(p + vec2(0.0, eps), time, 4, 2.0, 0.5) * amplitude; + + // Calculate normal from height differences + vec3 tangent = normalize(vec3(eps, 0.0, hx - h)); + vec3 binormal = normalize(vec3(0.0, eps, hy - h)); + normalContrib = normalize(cross(binormal, tangent)); + + return vec3(0.0, h, 0.0); // Only vertical displacement for noise + } + + // ============ Gerstner Wave Function ============ // Gerstner wave function - higher steepness = spikier waves vec3 gerstnerWave(vec2 pos, float time, vec2 direction, float steepness, float wavelength, out vec3 tangent, out vec3 binormal) { float k = 2.0 * 3.14159 / wavelength; @@ -515,49 +582,47 @@ vec3 binormal = vec3(0.0, 0.0, 1.0); vec3 t, b; - // === Large primary waves === - displacement += gerstnerWave(pos, time, vec2(1.0, 0.2), 0.42 * heightMod, 6.0, t, b); + // ============ GERSTNER WAVES - Large Scale Motion ============ + // Primary ocean swells + displacement += gerstnerWave(pos, time, vec2(1.0, 0.2), 0.45 * heightMod, 8.0, t, b); tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - displacement += gerstnerWave(pos, time * 1.1, vec2(0.4, 1.0), 0.35 * heightMod, 5.0, t, b); + displacement += gerstnerWave(pos, time * 1.1, vec2(0.4, 1.0), 0.38 * heightMod, 6.0, t, b); tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - // === Medium waves === - displacement += gerstnerWave(pos, time * 0.9, vec2(-0.6, 0.8), 0.25 * heightMod, 3.0, t, b); + // Secondary waves + displacement += gerstnerWave(pos, time * 0.9, vec2(-0.6, 0.8), 0.28 * heightMod, 4.0, t, b); tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - displacement += gerstnerWave(pos, time * 1.2, vec2(0.8, -0.5), 0.2 * heightMod, 2.2, t, b); + displacement += gerstnerWave(pos, time * 1.15, vec2(0.8, -0.5), 0.22 * heightMod, 3.0, t, b); tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - displacement += gerstnerWave(pos, time, vec2(-0.3, -0.9), 0.18 * heightMod, 1.8, t, b); + // Medium waves + displacement += gerstnerWave(pos, time, vec2(-0.3, -0.9), 0.18 * heightMod, 2.0, t, b); tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - // === Small detail waves === - displacement += gerstnerWave(pos, time * 1.2, vec2(0.9, -0.4), 0.12 * heightMod, 1.2, t, b); - tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); + // ============ PERLIN/SIMPLEX NOISE - Small Scale Detail ============ + // Only apply noise detail when close enough to see it + float detailFade = smoothstep(200.0, 50.0, distToCamera); - displacement += gerstnerWave(pos, time * 0.9, vec2(-0.5, -0.7), 0.10 * heightMod, 1.0, t, b); - tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - - displacement += gerstnerWave(pos, time * 1.3, vec2(0.3, 0.95), 0.08 * heightMod, 0.8, t, b); - tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - - // === Tiny ripples === - displacement += gerstnerWave(pos, time * 2.0, vec2(0.9, 0.1), 0.05 * heightMod, 0.35, t, b); - tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - - displacement += gerstnerWave(pos, time * 2.2, vec2(-0.2, 0.95), 0.04 * heightMod, 0.25, t, b); - tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - - // === Micro ripples for fine surface detail === - displacement += gerstnerWave(pos, time * 2.5, vec2(0.7, -0.7), 0.03 * heightMod, 0.18, t, b); - tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - - displacement += gerstnerWave(pos, time * 3.0, vec2(-0.8, 0.6), 0.025 * heightMod, 0.12, t, b); - tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); - - displacement += gerstnerWave(pos, time * 3.5, vec2(0.5, -0.9), 0.02 * heightMod, 0.08, t, b); - tangent += t - vec3(1.0, 0.0, 0.0); binormal += b - vec3(0.0, 0.0, 1.0); + if (detailFade > 0.01) { + vec3 noiseNormal; + + // Medium frequency noise ripples + vec3 noise1 = noiseWave(pos, time * 0.8, 0.3, 0.15 * heightMod * detailFade, noiseNormal); + displacement += noise1; + tangent += (noiseNormal - vec3(0.0, 0.0, 1.0)) * 0.3 * detailFade; + + // High frequency noise for fine detail + vec3 noise2 = noiseWave(pos, time * 1.2, 0.8, 0.08 * heightMod * detailFade, noiseNormal); + displacement += noise2; + tangent += (noiseNormal - vec3(0.0, 0.0, 1.0)) * 0.2 * detailFade; + + // Very fine ripples + vec3 noise3 = noiseWave(pos, time * 1.5, 2.0, 0.04 * heightMod * detailFade, noiseNormal); + displacement += noise3; + tangent += (noiseNormal - vec3(0.0, 0.0, 1.0)) * 0.1 * detailFade; + } // Store wave height for fragment shader v_waveHeight = displacement.y;