Task 5 of 6

Ping-Pong the Whole Landscape

Four kernels, three fields, one hundred steps. The loop lives in JavaScript, the grids live on the GPU, and the discipline is exactly the one Reaction–Diffusion and Cellular Automata already drilled — with one extra wrinkle worth naming.

Each step is ordered: dropTotal runs first, because the other three read the grid it produces. Then moveWater, moveSediment and erode all read the same snapshot of height, water and sediment — plus that fresh drop grid — and only when all three have returned do you swap. Overwrite height early and moveWater starts routing over terrain that has already been cut, which is a different simulation and a worse one.

Nothing here is pipelined: each kernel hands JavaScript an ordinary array and gets one back. That works, and it costs a round trip per pass — Pipelines & Textures shows how to keep the whole thing resident on the card with pipeline: true and immutable: true, which is the production answer once the grid stops being 64×64.

Goal: run STEPS steps of the whole model, recording the sediment in flight and the deepest water each step, then plot both.

Requirements

Hint 1 — the loop body
const drop = await dropTotal(height, water);
const nextWater = await moveWater(height, water, drop);
const nextSediment = await moveSediment(height, water, sediment, drop);
const nextHeight = await erode(height, water, sediment, drop);
height = nextHeight;
water = nextWater;
sediment = nextSediment;

Four awaits in order. Never Promise.all them: three of the four need the first one's answer.

Hint 2 — the traces

totalOf and maxOf are written for you. After the swap:

carried.push(totalOf(sediment));
deepest.push(maxOf(water));

and after the loop, plot({ 'sediment in flight': carried }, { title: '…' }).

Hint 3 — what the curves should look like

Sediment climbs, bends over around step 60 as pick-up and settling come into balance — and then, around step 80, kicks upward again: that second climb is the two hollows turning into lakes, and it shows up in the other plot at the same moment as a step in the deepest water. From there the deepest cell keeps climbing, with a sawtooth on it, because a lake surface trades a little water back and forth with its rim every step. Drag the rainfall slider and watch both curves scale.

Same idea elsewhere

Buying quality with time instead of work per frame is the same trade a progressive path tracer makes, and the same one a physically based fluid sim makes: the per-step kernel is cheap and stupid, and the result comes from running it enough times. Every one of them ping-pongs two sets of buffers, on every API there is.

All tasks in Hydraulic Erosion: Carving Terrain by Accumulation

  1. Seeing the Ground
  2. Which Way Is Down
  3. Everybody Downhill At Once
  4. Capacity: What the Water Can Carry
  5. Ping-Pong the Whole Landscape
  6. Two Hundred Steps, and a River Appears

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.