b3d-water
Water plane with reflections, waves, and underwater fog effect.
Demo
A lake with a few crates on the shore. The sun rakes across the surface; the water reflects the sky and the crates. Drag to orbit — dip the camera below the surface and the world tints and dims.
import { b3d, b3dSkybox, b3dWater, b3dReflections, b3dGround, sceneDelta } from 'tosijs-3d'
import { demoSun, orbitCam, spinner } from 'demo-utils'
const scene = b3d(
{
sceneCreated(el, BABYLON) {
orbitCam(el, { radius: 24, beta: Math.PI / 2.8, target: [0, 0.4, 0] })
// crates floating ON the surface (bottom at the water line), bobbing on the swell
const a = spinner(el, { x: -5, y: 1.0, z: -3, size: 2, spin: 0.12 })
const b = spinner(el, { x: 4.5, y: 0.7, z: 4, size: 1.4, spin: -0.18 })
let t = 0
el.scene.registerBeforeRender(() => {
t += sceneDelta(el.scene)
a.position.y = 1.0 + Math.sin(t * 1.1) * 0.14
b.position.y = 0.7 + Math.sin(t * 1.5 + 1) * 0.14
})
},
},
demoSun(),
b3dSkybox({ timeOfDay: 9 }),
// a textured seafloor, visible through the translucent water — gives the surface real depth
b3dGround({ y: -1.2, width: 60, height: 60, texture: 'checker', textureTiles: 20, color: '#3a5f6b' }),
b3dWater({ waterSize: 60, waveHeight: 0.4, windForce: -4, twoSided: true }),
b3dReflections(),
)
preview.append(scene)
tosi-b3d { width: 100%; height: 100%; }
Attributes
| Attribute | Default | Description |
|---|---|---|
waterSize |
128 |
Size of the water plane |
subdivisions |
32 |
Mesh subdivisions |
twoSided |
false |
Render both sides |
follow |
false |
Ride the camera in x/z (endless sea): the plane snaps to a coarse grid under you, ripples stay anchored in world space |
windForce |
-5 |
Wind strength |
waveHeight |
0 |
Wave amplitude |
bumpHeight |
0.1 |
Normal map bump intensity |
waterColor |
'#0066cc' |
Water tint color |
colorBlendFactor |
0.1 |
How much color tints the water |
spherical |
false |
Use a sphere instead of a plane |
Underwater Effect
When the camera goes below the water surface, a blue fog is automatically applied.
The sun (if present via b3dSun) is also dimmed based on depth.
import { b3d, b3dWater, b3dSun, b3dSkybox } from 'tosijs-3d'
document.body.append(
b3d({},
b3dSun({}),
b3dSkybox({ timeOfDay: 12 }),
b3dWater({ y: -0.2, twoSided: true, waterSize: 1024, normalMap: '/waterbump.png' })
)
)