NatureGL Firev1.0.0

Guides

Wind and obstacles

Buoyancy lifts the hot gas, and turbulence and vorticity confinement keep it curling. Wind bends it, and solid spheres and boxes deflect it. A moving obstacle pushes the gas out of its way.

campfire with params.wind ramped from 0.35 up to about 3 m/s and back. The flame leans harder near the top, because the wind grows with height.

#Wind

js
fire.setWind(2);                      // m/s along params.windDirection
fire.setWind(1.2, [0, 0, -1]);        // strength + direction
fire.params.wind = 0.5;               // or set the params directly
ParamDefault
wind0Strength in m/s. Negative values blow the other way (the demo slider runs from −4 to 4)
windDirection[1, 0, 0.18]Direction. Only x and z are used

Wind is horizontal and grows with height: the target speed runs from 0.35× wind at the domain floor to 1.35× at the top. The gas is dragged toward it gradually rather than set to it, so gusts ease in.

campfire after fire.setWind(2.4): the flame and smoke lean downwind.

#Turbulence and vorticity

params.turbulence (default 1) scales two things together:

  • Noise forcing. Two octaves of scrolling 3D noise push the gas. It only acts where there is heat or smoke, so still air stays still.
  • Vorticity confinement. The solver finds the curl of the velocity field and pushes it back into small vortices that numerical diffusion would otherwise smooth away. Its gain is 1.2 + 2.4 × turbulence.

params.buoyancy scales the lift of hot gas, and smoke adds a little weight. Keep turbulence within about 0–2. The confinement gain is in per-cell units, and much larger gains run away.

#Obstacles

js
const rock = fire.addObstacle({ type: 'sphere', position: [0.35, 3, 0.1], radius: 0.6 });
const beam = fire.addObstacle({ type: 'box', position: [0, 4, 0], size: [3, 0.3, 0.4] });

rock.position.x = 1;        // move it: the gas is pushed out of the way
rock.enabled = false;
beam.remove();              // or fire.removeObstacle(beam)

Obstacles are rasterised into a solid mask once per frame. Inside one, the fields are empty and the velocity is the obstacle's own measured velocity (clamped to 6 m/s). A moving sphere drags and pushes gas like a paddle.

A 0.6 m sphere obstacle swept side to side above the campfire. The flame parts around it and gets pushed along with it.
  • Up to 4 obstacles are simulated. addObstacle() warns when you add a fifth, and the extras are ignored.
  • They're fully solid, with no partial occupancy. An obstacle thinner than one grid cell (about 6 cm on high) is lost.
  • The obstacle is only a boundary for the gas. Draw a mesh for it yourself: the demo copies fire.obstacles[0].position onto its metal sphere every frame.
  • Positions are world metres. In a preset file, they're relative to the domain floor centre.
The demo's obstacle sphere (the O key) above the campfire. The flame and smoke split around it.

#The domain box

The fire only exists inside domain, which is set at creation (default: centre (0, 3, 0), size (4, 6, 4)). The grid has cubic cells of size.x / n, where n is the tier's cell count across x. The floor is closed. The sides and the top are open: fields fade in the last few cells, so gas leaves the box instead of piling up against the walls.

js
fire.domain;   // { min, size, center } in world units
fire.grid;     // { nx, ny, nz, cell }, e.g. 64 × 96 × 64 with 0.0625 m cells on high