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
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| Param | Default | |
|---|---|---|
wind | 0 | Strength 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
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.
- 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].positiononto its metal sphere every frame. - Positions are world metres. In a preset file, they're relative to the domain floor centre.
#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.
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