NatureGL Weatherv1.1.0

Guides

Lightning and thunder

Branching bolts, multi-pulse flashes that light your scene and the fog, and thunder that arrives when sound would. Strikes fire on their own at a rate you set, or on demand, and every one raises an event.

thunderstorm at night: three weather.strike() calls at 140, 260 and 190 m on top of the preset's automatic strikes. The flash lights the cobbles, the rain and the fog around the bolt.

#Automatic strikes

js
weather.set({ lightning: 0.5 });   // 0 = manual strikes only, 1 = a storm

lightning (0–1) is the strike frequency. Above 0.05, strikes fire automatically. The gap between them is lerp(22, 2.5, lightning) seconds, randomised ×0.4 to ×1.6: about every 22 s at the low end and every 2.5 s at 1. thunderstorm uses 0.85. Loading a preset with lightning > 0 arms the first strike 1.5 s later, so a storm starts promptly.

Lightning also raises state.cloud to at least state.lightning.

#Strike on demand

js
weather.strike();                                         // random, roughly ahead of the camera
weather.strike({ distance: 150 });                        // random direction, 150 m away
weather.strike({ position: new THREE.Vector3(80, 0, -200) });   // this ground point

Without a position, the bolt lands 110–370 m from the camera (lightning.minDistance / maxDistance), within about ±46° of where the camera faces. Its top is 85–125 m above the ground point. strike() works at any lightning value, including 0.

A strike 200 m out, looking past the houses. The bolt is a set of glowing ribbons built by recursive midpoint displacement, with side branches.

#Events

js
const off = weather.on('strike', e => {
  console.log(`strike ${e.distance.toFixed(0)} m away, thunder in ${e.delay.toFixed(1)} s`);
});
weather.on('thunder', e => shakeCamera(120 / e.distance));   // when the sound arrives
off();                                                       // unsubscribe

Both events carry the same StrikeEvent:

Field
positionGround point of the bolt (Vector3)
topCloud end of the bolt
directionUnit vector from the camera to top
distanceMetres from the camera, horizontally
delaySeconds until the thunder: distance / 343

'strike' fires immediately. 'thunder' fires delay seconds later, from inside update().

#The flash

Each strike is four pulses over about half a second: full strength, then 0.55, 0.85 and a random last one, each decaying fast. The flash ends 1.5 s after the strike.

Output
weather.lightning.flashCurrent flash, 0 to about 1.5
weather.lightning.flashDirectionUnit vector from the camera to the last bolt's top
weather.lightning.thunderInSeconds until the last strike's thunder (negative once it has arrived)
weather.lightning.lastStrikeThe last StrikeEvent, or null
weather.lightning.flashLightThe flash DirectionalLight (intensity = flash × 7), or null
weather.lightning.flashHemiThe flash HemisphereLight (intensity = flash × 2.2), or null

The flash also lights the rain and snow, and in weather.render() it lights the fog volume around the bolt.

#Flash your own lights

Pass lights: false to create() if you'd rather light the scene yourself. Then read flash every frame:

js
const weather = await WeatherSystem.create({ renderer, scene, camera, lights: false });

renderer.setAnimationLoop(() => {
  weather.update(dt);
  stormLight.intensity = weather.lightning.flash * 5;
  skyMaterial.uniforms.flash.value = weather.lightning.flash;   // light your own clouds
  weather.render();
});

The demo sky does exactly this with sky.setFlash(weather.lightning.flash, weather.lightning.flashDirection).

#Thunder

Thunder audio is synthesized noise, low-passed more for distant strikes, and quieter with distance. It needs a user gesture before the browser will play it:

js
button.addEventListener('click', () => weather.audio.unmute());
weather.audio.volume = 0.5;   // master volume, default 0.7
weather.audio.mute();

The same WeatherAudio plays the rain hiss and the gusting wind. It's muted by default.

From drizzle to thunderstorm with one loadPreset call. The wind picks up, the time eases to 21:30, and the first automatic strike follows 1.5 s after the call.