Visual Computing/Smoke Simulation
4 / 67

02/2022Visual Computing

Smoke Simulation

A grid-based smoke simulation in C++ that solves the incompressible Navier–Stokes equations on a Eulerian grid — semi-Lagrangian advection, a Gauss–Seidel pressure projection, and vorticity confinement to keep the swirl alive.

╌╌╌╌

A physics-based smoke simulation in C++. The fluid lives on a fixed 2D Eulerian grid (the solver runs on a lattice of cells) with velocity, pressure, vorticity, and smoke density stored per grid node, advanced by the Navier–Stokes equations and rendered as drifting smoke.

Smoke behaves as an incompressible fluid, so its velocity field obeys momentum balance under pressure, viscosity, and external forces, together with a divergence-free constraint:

Each timestep runs the same four-step sequence: inject smoke and velocity at the sources, advect the fields, apply vorticity confinement, and project the velocity back to a divergence-free state.

Each timestep runs the same cycle: inflow sources seed velocity, semi- Lagrangian advection carries the fields, vorticity confinement restores lost curl, and the pressure projection makes the velocity divergence-free before the next step begins.
Algorithm:Advance(Δt)\textsc{Advance}(\Delta t) — one timestep of the grid solver
  1. 1
    state: velocity uu, pressure pp, smoke density dd on the 128×64128 \times 64 grid
  2. 2
    inject sources: add inflow velocity and density at the emitters
  3. 3
    uu \gets advect uu through itself (semi-Lagrangian, RK2 backtrace)
  4. 4
    dd \gets advect dd through uu
  5. 5
    uu+Δtfconfu \gets u + \Delta t \, f_{\text{conf}} (vorticity confinement, ε=4\varepsilon = 4)
  6. 6
    solve 2p=u\nabla^2 p = \nabla \cdot u by Gauss-Seidel, 40 sweeps
  7. 7
    uupu \gets u - \nabla p (project back to divergence-free)
A miniature Eulerian smoke solver on a 72-by-36 grid: a bottom emitter, semi-Lagrangian advection, Gauss-Seidel pressure projection. The toggle adds the vorticity-confinement force, which pushes velocity back up the gradient of curl magnitude — on, the plume holds its small-scale swirls as it rises; off, the coarse grid's numerical diffusion irons it into a smooth laminar column.
Grid smoke solver
bottom-center emitter feeding a rising plume

A handful of inflow emitters seed the motion: grid nodes within a small radius of an emitter take its velocity, with radial, tangential, and mixed emitters set around the domain. The fields then move by semi-Lagrangian advection, which updates a node by tracing the velocity field backward (a midpoint half-step, then a full step) and bilinearly interpolating the old field at the departure point. Tracing backward and interpolating this way is unconditionally stable, which is what lets the smoke take large steps without blowing up.

Advection leaves the velocity field with nonzero divergence, so a projection step restores . The solver takes the divergence by central differences, solves the Poisson equation with forty Gauss–Seidel sweeps, and subtracts the pressure gradient from the velocity.

Discretizing the fluid numerically damps small-scale rotation, so the smoke loses its curl and goes limp. Vorticity confinement measures the local vorticity , builds unit vectors pointing up the gradient of toward its concentrations, and adds the force — with confinement strength in the code — back into the velocity, restoring the swirling detail that makes rising smoke read as smoke.

References

  1. Project repository

╌╌ END ╌╌