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;