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' })
  )
)