Start here
Quick start
An ocean with the built-in sky and a row of floating boxes in an ordinary three.js scene. This is examples/basic/, step by step.
#Set up the renderer
water.render() does its own tone mapping (ACES by default), so leave renderer.toneMapping at its default, NoToneMapping.
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { WaterSystem } from 'naturegl-water';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);#Build your scene as usual
NatureGL Water works in metres, with sea level at y = 0. Give the camera a far plane that reaches the horizon.
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(55, innerWidth / innerHeight, 0.3, 12000);
camera.position.set(0, 7, 26);
const controls = new OrbitControls(camera, renderer.domElement);
controls.maxPolarAngle = Math.PI * 0.49;#Create the water
create() adds the ocean mesh and the built-in sky dome to your scene.
const water = await WaterSystem.create({
renderer, scene, camera,
quality: 'high', // low | medium | high | ultra
preset: 'tropical',
});#Add lights that follow the sky
bindLights points a DirectionalLight at the current key light (the sun by day, the moon at night) and colours a HemisphereLight from the sky. Call it every frame.
const sun = new THREE.DirectionalLight();
const hemi = new THREE.HemisphereLight();
scene.add(sun, sun.target, hemi);#Float some objects
One probe makes an object bob like a buoy. size places four probes (bow, stern, port, starboard), so the object also pitches and rolls.
const colors = [0xd9534f, 0xf0ad4e, 0x5bc0de, 0x5cb85c, 0xeeeeee];
for (let i = 0; i < 5; i++) {
const size = 1.5 + i * 0.6;
const box = new THREE.Mesh(
new THREE.BoxGeometry(size, size * 0.6, size * 1.6),
new THREE.MeshStandardMaterial({ color: colors[i], roughness: 0.6 }),
);
box.position.set((i - 2) * 6, 0, Math.sin(i) * 5);
scene.add(box);
water.buoyancy.addObject(box, i === 0
? { draft: 0.2 } // single probe
: { size: { length: size * 1.6, beam: size }, draft: size * 0.15 }); // four probes
}#Update, then render
Call update(dt) once per frame after you move your objects, then render(). It draws your scene into an HDR target with depth, puts the water over it, adds bloom and tone-maps to the canvas. It also picks up canvas size changes on its own.
const timer = new THREE.Timer();
renderer.setAnimationLoop(t => {
timer.update(t);
controls.update();
water.update(timer.getDelta());
water.bindLights(sun, hemi);
water.render();
});
addEventListener('resize', () => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
});#Change the sea
water.loadPreset('storm'); // eases over about 1.5 s
water.loadPreset('sunset', { instant: true }); // snap
water.setParams({ wind: 12, time: 18.2 }); // a few values, eased
water.setParams({ clouds: 0.8 }, { instant: true });
water.stats.significantWaveHeight; // metres, for a HUD#Add a coastline
If your scene has terrain, give the water its height function. Waves then shoal over the shallows and break on the beach.
water.setBathymetry({
heightAt: (x, z) => terrainHeight(x, z), // > 0 is land, sea level is 0
bounds: { minX: -400, minZ: -400, maxX: 400, maxZ: 400 },
});