diff --git a/public/tide-pool-world.js b/public/tide-pool-world.js
index a47a9a6..227d206 100644
--- a/public/tide-pool-world.js
+++ b/public/tide-pool-world.js
@@ -382,7 +382,10 @@ function sediment(world, dt) {
for (let j = 0; j < ROWS; j++) for (let i = 0; i < COLS; i++) {
const k = j * COLS + i, d = w[k] - h[k] - wall[k];
// Water too thin to hold anything drops what it carried.
- if (d < WET) { if (silt[k] > 0) { sand[k] += silt[k]; h[k] += silt[k]; changed += silt[k]; silt[k] = 0; } continue; }
+ if (d < WET) {
+ if (silt[k] > 0) { sand[k] += silt[k]; h[k] += silt[k]; changed += silt[k]; silt[k] = 0; if (w[k] < h[k] + wall[k]) w[k] = h[k] + wall[k]; }
+ continue;
+ }
const u = ((i > 0 ? qx[k - 1] : 0) + qx[k]) * .5 / d, v = ((j > 0 ? qz[k - COLS] : 0) + qz[k]) * .5 / d;
const over = Math.hypot(u, v) - LIFT, room = over > 0 ? CARRY * d * over * over : 0;
if (silt[k] < room) {
@@ -392,6 +395,7 @@ function sediment(world, dt) {
} else if (silt[k] > room) {
const fall = Math.min((silt[k] - room) * SETTLE * dt, silt[k]);
sand[k] += fall; h[k] += fall; silt[k] -= fall; changed += fall;
+ if (w[k] < h[k] + wall[k]) w[k] = h[k] + wall[k];
}
}
// Across each face the flow carries its share of the sand held in the cell it leaves; out past the edge, the sea keeps it.
diff --git a/public/tide-pool.js b/public/tide-pool.js
index dcd43e8..57d9500 100644
--- a/public/tide-pool.js
+++ b/public/tide-pool.js
@@ -1,7 +1,7 @@
import {
createWorld, advanceWorld, offerObject, SPECIES, SPECIES_ORDER, CELL, COLS, ROWS, X0, Z0, X1, Z1, START_POOL, waterLevel, daylight,
- heightAt, surfaceAt, depthAt, onShelf, bodyAt, tideOf, tideRising, label, goalText, describeWorld, creatureById, MACHINES, BLOCK, BLOCK_Y0, blockKey, footAt, debrisAt, footing, stormAt, shineLantern, douseLantern, moonlight,
-} from './tide-pool-world.js?v=38';
+ heightAt, surfaceAt, depthAt, onShelf, bodyAt, tideOf, tideRising, label, goalText, describeWorld, creatureById, MACHINES, BLOCK, BLOCK_Y0, blockKey, footAt, debrisAt, footing, stormAt, shineLantern, douseLantern, moonlight, SWELL, swellHeight,
+} from './tide-pool-world.js?v=39';
const root = document.querySelector('[data-tide-pool]');
const status = document.querySelector('#tide-status');
@@ -156,6 +156,10 @@ async function initialize() {
planktonTexture.magFilter = planktonTexture.minFilter = T.LinearFilter; planktonTexture.needsUpdate = true;
shared.uPlankton = { value: planktonTexture };
shared.uHaze = { value: new T.Vector4(0, 1, 0, 0) }; shared.uHazeZoom = { value: 7 };
+ // The swell the simulation brings in at its seaward edge, so the open sea beyond carries the same waves on.
+ shared.uSwell = { value: SWELL.map(s => new T.Vector4(s.a, s.kx, s.kz, s.w)) };
+ shared.uSwellPhase = { value: new T.Vector3(...SWELL.map(s => s.phase)) };
+ shared.uSwellLift = { value: 1 };
shared.uHazeColor = { value: new T.Color(0x1a1524) };
// The simulation grid as a texture: r = water surface, g = ground, b = set stone, a = how damp the ground still is.
// Sampled with a cubic B-spline (four bilinear taps) so shorelines and hollows come out round, not grid-shaped.
@@ -354,6 +358,7 @@ async function initialize() {
uGrid: shared.uGrid, uGridBox: shared.uGridBox, uFlow: shared.uFlow, uOpen: { value: 0 }, uTide: shared.uWater,
uLamps: shared.uLamps, uLampColor: shared.uLampColor, uNight: shared.uNight, uDusk: shared.uDusk, uStorm: shared.uStorm,
uWakes: shared.uWakes, uPlankton: shared.uPlankton, uMoon: shared.uMoon,
+ uSwell: shared.uSwell, uSwellPhase: shared.uSwellPhase, uSwellLift: shared.uSwellLift,
uHaze: shared.uHaze, uHazeZoom: shared.uHazeZoom, uHazeColor: shared.uHazeColor },
vertexShader: `${GRID}
uniform float uOpen, uTide, uTime, uStorm; varying vec3 vW; varying float vDepth; varying vec2 vSlope;
@@ -375,6 +380,7 @@ async function initialize() {
uniform vec4 uLamps[${LAMPS}]; uniform vec3 uLampColor, uHazeColor; uniform float uNight, uDusk, uHazeZoom, uStorm; uniform vec4 uHaze;
uniform vec4 uWakes[${WAKES}]; uniform sampler2D uPlankton; uniform float uMoon;
uniform sampler2D uFlow; uniform vec4 uGridBox; uniform float uOpen;
+ uniform vec4 uSwell[3]; uniform vec3 uSwellPhase; uniform float uSwellLift;
${WAVES}
float foamHash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); }
// Foam lace: the walls between cells scattered over the surface, as the bubbles of spent foam draw them.
@@ -401,6 +407,11 @@ async function initialize() {
vec2 g1 = waveSlope(vW.xz - flow * t1 * 2.2, uTime, 1.4), g2 = waveSlope(vW.xz - flow * t2 * 2.2, uTime, 1.4);
// A storm roughs the water up.
vec2 g = mix(g1, g2, abs(2. * t1 - 1.)) * smoothstep(.01, .25, d) * 1.3 * detail * (1. + uStorm * 1.6) + vSlope * 1.6;
+ // Out on the open sea the swell's slope comes straight from the waves themselves.
+ if (uOpen > .5) for (int i = 0; i < 3; i++) {
+ vec4 s = uSwell[i];
+ g += s.yz * s.x * uSwellLift * cos(s.y * vW.x + s.z * (vW.z - ${Z1.toFixed(2)}) + s.w * uTime + uSwellPhase[i]) * 1.6;
+ }
vec3 n = normalize(vec3(-g.x, 1., -g.y));
// Depth: a clear lavender-grey in the shallows, deep violet where the water is deep.
float absorb = 1. - exp(-d * 1.3);
@@ -1600,6 +1611,7 @@ async function initialize() {
shared.uHaze.value.set(-Math.sin(YAW), -Math.cos(YAW), view.x, view.z);
shared.uHazeZoom.value = view.zoom;
shared.uWater.value = waterLevel(world);
+ shared.uSwellLift.value = swellHeight(world);
uploadGrid();
uploadFlow();
if (night > .02) { uploadPlankton(1 / 30); gatherWakes(); }
diff --git a/src/components/tide-pool.tsx b/src/components/tide-pool.tsx
index 3f0ea2e..d4f823c 100644
--- a/src/components/tide-pool.tsx
+++ b/src/components/tide-pool.tsx
@@ -142,7 +142,7 @@ export function TidePoolContent() {
{/* Lets the three.js add-ons resolve the same pinned module the page already uses. */}
-
+
);
}