More
Troubleshooting
The common problems, what causes them, and the fix for each.
I see my scene but no water
Check three things. You call water.render() instead of renderer.render(scene, camera): the water lives in an overlay scene that only render() draws. You call water.update(dt) at least once after adding bodies, since that's when meshes are built (render() also builds them if needed). And the path's y values are the water level, so a river whose y sits below your terrain is hidden under it.
The water floats above the ground, or the ground pokes through it
The terrain doesn't match the water. Build the ground from water.carveTerrain(heightFn), and call it again after adding or removing bodies: it's a snapshot. If you sculpt terrain by hand, set each river's y a little above your bed.
Hard lines where two rivers meet
Overlapping rivers at the same level z-fight. End one river inside a lake (the end fades automatically with fade: 'auto'), or overlap them only where their levels differ. River-to-lake joins fade on their own.
The ribbon folds or tears in a tight bend
A bend whose radius is smaller than the river's half width folds the ribbon over itself. Widen the bend, add path points to smooth it, or narrow the river there with widths.
Water continues past the top of my waterfall
Give the upstream river extend: [0, 0] so it stops at the lip, and make sure its level equals the waterfall's top.y. The lip clip discards water at top.y beyond the lip line, but only for the first 4 waterfalls, and only with clipUpstream: true.
My transparent objects vanish behind the water
Transparent objects are drawn in the world pass, before the water. Most don't write depth, so the water surface covers any part of them that sits in front of it. Where you can, make them opaque with alphaTest instead of blending.
Post-processing ignores the water
render() owns the frame. Pass a render target, water.render(myTarget), and run your post chain on that target's texture afterwards.
My fog or exposure keeps getting reset
By default the preset owns them. Create the system with manageFog: false or manageExposure: false to take them over. With manageFog off, the water still reads whatever THREE.Fog or THREE.FogExp2 your scene has.
My sun light ignores the preset, or ignores my own settings
The preset only drives lights passed to bindLights(), and only while the built-in sky is active. After setSky(sky), the external sky owns the lights. To control a light yourself, don't bind it.
No caustics or wet rocks
Only materials passed to patchMaterial() get them. Check that water.caustics and water.wetness aren't 0, and that the material is a MeshStandardMaterial or MeshPhysicalMaterial. Lambert and Phong get caustics but not the glossy wet band.
The camera goes under the water and everything looks wrong
There is no underwater rendering. Use water.isUnderwater() or sampleHeight() to keep the camera above the surface, the way the demo clamps it to 0.45 m above the higher of the ground and the water.
The render looks soft
On low and medium the world target renders at 0.7 and 0.85 of the drawing buffer. Use high or ultra, and don't cap the pixel ratio below 1.
Rocks far from the camera lose their foam rings
Only the nearest maxObstacles obstacles are used each frame: 12, 24, 40 or 64 depending on the tier. Raise the tier, or remove obstacles that are never seen.