Guides
With other packs
NatureGL River renders your scene through its own depth pipeline, and everything else it offers is data you can read. That makes it easy to feed it a sky and to give other packs its terrain and water queries.
#The contract
render()owns the frame. It draws your scene into a HalfFloat target with a depth texture, composites that to the screen and draws the water on top. A depth pipeline is unavoidable for water that absorbs light by thickness.- Your scene stays yours. The only object the system adds to it is the optional sky dome. Water surfaces, cascades and particles live in a separate overlay scene.
- Inputs are plain objects.
setSky()accepts anything sky-like, andbindLights()takes ordinary three.js lights. - Outputs are plain functions and values.
carveTerrain()returns a height function,sample()/sampleHeight()/sampleFlow()/isInWater()answer on the CPU, andlightingholds the current sun, ambient, fog and exposure.
#With NatureGL Sky
NatureGL Sky's SkySystem exposes sun.direction, sun.color, sun.intensity, an equirect envMap, cloudShadow ({ texture, matrix }) and fogColor. Those are the fields setSky() reads, so you can pass the sky itself.
import { SkySystem } from 'naturegl-sky';
import { RiverSystem } from 'naturegl-river';
const sky = await SkySystem.create({ renderer, scene, camera, preset: 'golden' });
const water = await RiverSystem.create({
renderer, scene, camera,
builtInSky: false, // NatureGL Sky draws the sky
manageExposure: false, // NatureGL Sky's auto exposure owns renderer.toneMappingExposure
});
water.setSky(sky); // sun, reflections, cloud shadows, fog colour
sky.bindLights(sun); // the sky drives the lights; NatureGL River stops driving them
renderer.setAnimationLoop(() => {
controls.update();
sky.update(dt); // after moving the camera
water.update(dt);
water.render(); // instead of renderer.render(scene, camera)
});- NatureGL Sky's backdrop is a mesh in your scene, so it lands in NatureGL River's world pass like any other geometry, and the water reflects it through
envMap. envMapandcloudShadow.textureare getters on the sky. NatureGL River reads them on every frame, so a sky quality change needs no re-plugging.- With
manageFogleft on, NatureGL River keeps aFogExp2on the scene in the sky'sfogColor, with the density from the River preset'slight.fogDensity. - NatureGL Sky's post pass
render(scene, camera)draws the scene itself, which would bypass the water. Use the sky without its post pass.
#With NatureGL Grass
NatureGL Grass places blades on any terrain described by a heightAt function. Give it the carved height, and use isInWater() as the grass mask so nothing grows in the river.
import { GrassSystem } from 'naturegl-grass';
const height = water.carveTerrain(baseHeight); // after adding every body
const grass = await GrassSystem.create({
renderer, scene, camera,
terrain: {
heightAt: height,
bounds: [-45, -45, 45, 45], // [minX, minZ, maxX, maxZ]
mask: (x, z) => (water.isInWater(x, z) ? 0 : 1),
},
});
water.bindLights(sun, hemi); // NatureGL River sets the light values from its preset…
grass.bindLights(sun, hemi); // …and NatureGL Grass reads them every update
renderer.setAnimationLoop(() => {
water.update(dt);
grass.update(dt);
water.render();
});isInWater() is false in the thin margin just past each bank, so the grass reaches the waterline. Use water.sample(x, z) with a tighter test, such as s && s.edge < 1.15, to keep a strip of bare bank.
#With NatureGL Weather
Both packs patch standard materials through a chained onBeforeCompile, so the same ground material can take rain wetness and river caustics:
weather.patchMaterial(groundMaterial, { ground: true });
water.patchMaterial(groundMaterial);#With NatureGL Water
NatureGL Water's WaterSystem also has a render() that owns the frame, so the two can't both render the same frame. Use NatureGL Water for open sea and NatureGL River for inland water.