Smoke and Fire

A fluid solver hands you one thing: a velocity field — at every cell of a grid, an arrow saying which way the air is moving and how fast. That is the machinery behind a stable fluids simulation. But nobody watches a velocity field. What audiences watch is smoke curling off a candle, a fireball blooming through a collapsing building, the greasy black plume off a burning car. This page is about the last mile: how you turn that invisible field of arrows into stuff you can see and believe.

The trick is to ride passengers on the flow. Smoke is a cloud of little particles too light to matter to the air but heavy enough to catch the light; we model that cloud as a density field that the velocity simply carries along. Fire adds heat — a temperature field, a reaction that turns fuel into hot expanding exhaust, and a colour that glows from deep red to white as it burns. Get three forces right — advection, buoyancy, and a swirl-preserving nudge called vorticity confinement — and dead grid data starts to roll like the real thing.

Smoke = a density field carried by the flow

Think of smoke as a dye poured into the air. The dye does not push the air around (it is passive); it just goes where the air already goes. We store its concentration as a scalar field \rho(\mathbf{x}, t) — a number in every grid cell, zero for clear air, high for thick smoke. Each step, that field is advected: transported along the velocity \mathbf{u}.

Advection alone gives you smoke that drifts, but not smoke that lives. A puff released into a still velocity field just sits there and slowly blurs. Two ingredients are missing: the reason smoke goes up, and the reason it curls.

Buoyancy: why smoke rises

Hot smoke is less dense than the cool air around it, so it floats up — the same reason a hot-air balloon climbs. In the simulation we add an upward buoyancy force to the velocity field wherever the fluid is hot or the smoke is light:

\mathbf{f}_{\text{buoy}} = \left(-\alpha\,\rho + \beta\,(T - T_{\text{amb}})\right)\,\hat{\mathbf{z}}

Read the two terms: -\alpha\,\rho pulls heavy smoke down (its own weight), while \beta\,(T - T_{\text{amb}}) lifts anything hotter than the ambient temperature T_{\text{amb}} up. The unit vector \hat{\mathbf{z}} points against gravity. Hot columns rise; as they rise they cool, buoyancy fades, and the plume flattens into the mushroom cap you always see. This coupling between temperature and motion is exactly what makes fire move like fire — kill it and flames just sit there like glowing fog.

A rising plume, drawn

Here is the anatomy of a plume. A hot source at the bottom feeds smoke upward under buoyancy (the vertical arrows). But as fast-moving smoke shears past slower surrounding air, the flow rolls up into a vortex — a spinning eddy — and it is those rolls, tumbling over one another, that give real smoke its restless, braided look. Reveal the steps to build the plume up.

The whole believability of the shot hinges on protecting that curl. And that is precisely what a plain grid solver quietly destroys.

Vorticity confinement: putting the swirls back

Every step, semi-Lagrangian advection interpolates between grid cells — and interpolation averages, which smooths. Averaging bleeds energy out of the smallest swirls first, so after a few frames the fine, high-frequency vortices are gone and you are left with a bland, over-smoothed blob. This is numerical dissipation: the grid acting like an unwanted viscosity, thick as syrup, damping out exactly the detail that makes smoke interesting.

Fedkiw, Stam and Jensen's answer (SIGGRAPH 2001) is vorticity confinement: measure where the swirl is being lost and inject a force that spins it back up. First compute the vorticity \boldsymbol{\omega} = \nabla \times \mathbf{u} — the local spin of the fluid. Then find the direction pointing toward the concentrated swirl, \mathbf{N} = \nabla|\boldsymbol{\omega}| / |\nabla|\boldsymbol{\omega}||, and add a force that curls around it:

\mathbf{f}_{\text{conf}} = \varepsilon\,h\,(\mathbf{N} \times \boldsymbol{\omega})

Because it only reinforces swirls that are already there, confinement restores the look of turbulence without you having to resolve every tiny eddy on the grid — a cheap fix that made low-resolution smoke suddenly filmable.

Worked example: why plain smoke looks dead, and how to revive it

Release a warm puff into a coarse 64^3 grid and run three versions of the same shot.

Version A — advection only. With no buoyancy the puff never rises; with no confinement, every step's interpolation averages neighbouring cells and dissipation eats the small vortices within a dozen frames. The result is a grey ball that expands and fades in place — the dreaded "cotton-wool" smoke. It is technically a fluid; it looks like a cloud of nothing.

Version B — add buoyancy. Now the warm puff climbs. As the rising core shears past still air, a vortex ring tries to form at the edges — good — but dissipation is still shaving those rolls flat almost as fast as they appear. You get a rising blob with a hint of a mushroom, still soft and lifeless around the edges.

Version C — add vorticity confinement. The confinement force feeds energy straight back into the nascent vortex ring, so the rolls survive, tighten, and cascade into finer curls. The same coarse grid now produces the characteristic curling, braided plume — smoke that tumbles over itself the whole way up. Nothing changed but one extra force term countering the grid's own numerical viscosity.

The lesson: buoyancy tells the smoke where to go; vorticity confinement is what keeps it alive on the way there.

Fire: heat, reaction, and glowing colour

Fire is smoke's hotter sibling. Everything above still holds, plus three additions.

A temperature field. Fire carries a scalar T(\mathbf{x},t) advected like density, but with strong buoyancy (it is very hot) and cooling as it radiates heat away.

A reaction. A fuel field ignites above a threshold temperature and burns: fuel converts to hot exhaust, releasing heat and expanding (the flow gains volume at the flame front, which is what makes explosions push outward). As the burn finishes, unburned carbon lingers as soot — that is the smoke that trails a cooling fire.

Blackbody colour. Hot matter glows, and the colour it emits depends only on its temperature — the blackbody spectrum. We map temperature straight to emitted colour:

T \uparrow: \quad \text{dull red} \;\to\; \text{orange} \;\to\; \text{yellow} \;\to\; \text{white}

Coolest flame edges glow deep red; the hottest core burns white-hot; and once temperature drops below the visible-glow threshold, the fuel is spent and you see only dark soot smoke. Because the colour is emitted (the fire makes its own light) it is rendered as an emissive volume, while the smoke above it is rendered by how it absorbs and scatters light passing through.

The visual pipeline

Zoom out and the whole thing is two stages. Simulate: advance the velocity, density and temperature fields on a grid each frame (advect, add buoyancy + confinement, project to keep the flow incompressible, react and cool). Render: march rays through the resulting volume, accumulating emission from hot cells (the fire's glow) and absorption/scattering from dense cells (the smoke), to produce the final image. Grid in, glowing image out.

Which half you can afford depends on your budget. Film actually runs the simulation — big grids, hours per frame, physically-grounded so it holds up in close-up and slow motion. Games almost never can: at 60 frames a second there is no time to solve a fluid, so they fake it — animated sprite sheets, scrolling procedural noise, a handful of GPU particles, and cheap tricks that read as smoke from a distance without solving a single equation. Same goal, opposite ends of the cost–fidelity trade.

A candle flame is that pointed teardrop entirely because of buoyancy. On Earth, hot combustion gases are lighter than the surrounding air, so they rush upward, stretching the flame into a rising tongue and pulling fresh oxygen in at the base. Take gravity away — light a candle on the Space Station — and there is no "up" for the hot gas to rise into. Buoyancy vanishes, the flame stops being drawn into a point, and it settles into a small, dim, blue sphere, fed only by slow diffusion of oxygen from every side. It is a lovely reminder that the shape of fire is not intrinsic to burning at all — it is the buoyancy term in disguise, which is exactly why a simulator that gets buoyancy right gets the silhouette of fire right.

The single most common way CG smoke goes wrong: it comes out soft, puffy and lifeless — "cotton-wool" smoke that expands and fades without ever rolling. The culprit is almost never your buoyancy or your colours; it is numerical dissipation. Every semi-Lagrangian advection step interpolates between cells, interpolation averages, and averaging smooths away the small-scale vortices that are the turbulent detail. The grid is acting like an invisible, unwanted viscosity.

The fixes all target that loss directly: turn on vorticity confinement to spin the swirls back up; raise the grid resolution so finer vortices survive; or add wavelet / procedural turbulence to synthesize high-frequency detail on top of the coarse solve. What you must not do is reach for more buoyancy or a fancier colour ramp — neither touches the missing curl, and you will just get a taller, prettier blob. Diagnose "no roll" as a dissipation problem, every time.

Cheerfully, yes. That roaring torch in your favourite game is very likely a looping sprite-sheet flipbook drawn by an artist, or a shader scrolling procedural noise upward with a colour gradient stuck on top — zero fluid dynamics, no grid, no solver. It works because from across a room your eye only needs the gestalt: warm colour, upward motion, flicker. The film version of the same torch might be a full volumetric simulation costing minutes of compute per frame, because a camera drifting past it in slow motion would instantly expose a repeating flipbook. The art of real-time VFX is knowing exactly how little physics you can get away with.