Guides
Rendering
Water needs to see what's behind and below it, so render() draws your scene into an HDR target with depth first and puts the water over it. This page covers the ways to call it, the overlay layer for effects that sit on top, and plugging in your own post chain.
#Three ways to draw
| Call | You get | Use it when |
|---|---|---|
water.render(target?) | Everything: refraction, depth foam, reflections, underwater effects, bloom, tone mapping | Almost always |
water.renderHDR() 1.1 | Passes 1–3 into a linear HDR target plus depth, no bloom or tone mapping | You have your own post chain, such as NatureGL Sky's post pass |
renderer.render(scene, camera) | The ocean with sky reflection, glitter, foam and crest scattering | You can't change the render loop. No refraction, depth foam, SSR, bloom or underwater effects |
#render()
renderer.setAnimationLoop(() => {
water.update(dt); // after moving your objects
water.render(); // to the canvas
});
water.render(myTarget); // or into a WebGLRenderTargetIt runs five passes:
#World
Your scene with the ocean hidden and the overlay layer masked out, into a HalfFloat target with a DepthTexture. MSAA is 4× on high and ultra. Shadows render here as usual.
#Water
The world colour and depth are copied into the HDR target, with underwater fog and light shafts where the near plane is below the surface. Then the ocean draws, sampling that colour and depth for thickness, refraction, depth blur, screen-space reflections and contact foam.
#Overlay
Objects on water.overlayLayer, depth-tested against the water surface.
#Bloom
A soft-knee prefilter, a 13-tap downsample chain and a tent upsample (bloomLevels: off on low, 4–6 mips above).
#Composite
Bloom, exposure, tone mapping, output colour space and dither, plus the underwater wobble and the waterline meniscus, into the canvas or target.
render() restores renderer.autoClear and the previous render target when it's done, and re-reads the drawing-buffer size every frame, so you don't need to call resize() after renderer.setSize.
#Tone mapping and exposure
const water = await WaterSystem.create({ renderer, scene, camera, toneMapping: 'aces' }); // 'aces' | 'reinhard' | 'none'The composite applies the tone mapping itself, so leave renderer.toneMapping at NoToneMapping when you use render(). water.exposure is the exposure it uses: the exposure param, times the external sky's displayExposure when there is one (see With other packs).
| Param | Default | |
|---|---|---|
exposure | 1 | Composite exposure |
bloom | 0.45 | Bloom strength |
bloomThreshold | 1.6 | Bloom threshold, in linear HDR |
#Transparent objects and the overlay layer
The world pass draws your whole scene before the water, so transparent objects there end up under the water surface. Put spray, rain, particles and other transparent effects on the overlay layer instead. They're drawn after the water and depth-tested against it.
spray.layers.set(water.overlayLayer); // layer 30 by defaultThe overlay pass switches the camera to that layer for its own draw, so you don't need to enable it on the camera. The demo's underwater particles use this.
Pick a different layer with create({ overlayLayer: 20 }). The water re-scans the scene for overlay objects twice a second and skips the pass when there are none.
#renderHDR() for your own post
const hdr = water.renderHDR(); // { texture, depthTexture }
myPost.render(hdr.texture, hdr.depthTexture);textureis the linear HDR colour of world, water and overlay, not tone-mapped.depthTextureholds world and water-surface depth.- The size is the drawing buffer times the tier's
renderScale(75 % on low, 90 % on medium, 100 % above). - The underwater colour grade is skipped. The underwater fog is kept.
The NatureGL Sky post pass composites straight over it. See Water and the sky's post pass.
#Profiling
water.profiling = true;
// a few frames later
water.gpuTimings; // { world, water, overlay, foam, bloom, composite, fft } in ms, smoothedTimings need EXT_disjoint_timer_query_webgl2. On a shared GPU they include other processes' work. See Quality and performance for what each tier costs.
#The subsystems
For advanced use, the parts are exposed: water.ocean (the mesh, frustum culling off, follows the camera), water.uniforms (shared by every water shader), water.pipeline (the render targets), water.spectrum, water.fft, water.foam, water.bathymetry and water.wakes.