Guides
Rain and splashes
Rain is a box of instanced streaks that wraps around the camera, so it's always falling where you look. Wind slants it, occluders stop it, and your lights make it glow.
downpour at dusk. The streaks catch the street lamps passed in as localLights, and splashes land on the cobbles and the roofs.#Turn it up
weather.set({ rain: 0.6 }); // eased toward the new target
weather.set({ rain: 1, wind: 0.7 }); // heavier, slanted harder
weather.loadPreset('drizzle'); // or take a preset's whole mixrain goes from 0 to 1. It scales the number of drops and splashes drawn, from the quality tier's count at 1 down to nothing. It also speeds the fall a little, from 8.5 to 10.5 m/s. At 1 you see the full count: 18k streaks on low up to 90k on ultra.
Rain also feeds everything else. It adds haze to the fog, raises state.cloud to at least rain × 0.9, wets patched surfaces and melts snow cover. The audio hiss follows it too. See Weather parameters for the formulas.
#How the streaks behave
- Camera-following. The streaks wrap in a 36 × 26 × 36 m box centred on the camera. Move anywhere and it's raining there; there is no emitter to place.
- Wind.
wind(0–1, where 1 is about 13 m/s before gusts) andwindDirection(radians, 0 = +x, π/2 = +z) slant the streaks. The direction wanders ±0.25 rad and the speed gusts on its own. - Motion blur. Each drop is a streak with a bright, rounded head and a fading tail, with per-drop brightness.
- Light. Drops are lit by the ambient light, the lightning flash and up to four local lights. Seen against the sun or moon they light up, like tiny lenses.
- Occlusion. Drops below the top-down occlusion map are culled, so it doesn't rain under roofs.
#Splashes
Splashes spawn on the occlusion surface within 16 m of the camera. That means roofs, walls and benches as well as the ground. They fade out as snow cover builds and are hidden entirely once cover reaches 90 %.
weather.rain.splashes = false; // the demo's "Splashes" toggle#Tuning the look
The RainSystem is weather.rain. Its look can be adjusted at runtime:
| Property | Default | |
|---|---|---|
opacity | 0.32 | Streak brightness |
streakLength | 0.55 | Streak length multiplier |
splashes | true | Splashes on or off |
dropCount, splashCount | from the tier | Instances drawn at intensity 1 |
intensity | Set by update() from state.rain. Write weather.set({ rain }) instead |
weather.rain.opacity = 0.22; // softer rain for a bright scene
weather.rain.streakLength = 0.8; // longer streaks#Lamps in the rain
Pass up to four point lights, or plain { position, color, intensity } objects, as localLights. The library reads them every frame, so animating their intensity just works. Their contribution to the rain, splashes and fog is color × intensity × localLightScale, and localLightScale defaults to 1/14.
const lamps = [lampA, lampB]; // THREE.PointLight
weather.setLighting({ localLights: lamps }); // once
// later: lampA.intensity = 14 * nightFactor; rain around it follows#Using RainSystem on its own
Every subsystem can run without the facade. Standalone, it creates its own uniforms and needs the camera in update:
import { RainSystem } from 'naturegl-weather';
const rain = new RainSystem({ scene }); // maxDrops 90000, maxSplashes 2400
rain.intensity = 0.7;
renderer.setAnimationLoop(() => {
rain.update(dt, camera);
renderer.render(scene, camera);
});Without the facade there's no occlusion map and no wind. The streaks fall straight down, aren't culled under roofs, and are lit by the default ambient in rain.uniforms.amb. You can write rain.uniforms.wind.value (m/s) yourself. For anything beyond a quick test, use WeatherSystem.