← Back

The Divergence-Free Constraint

2026-04-04

The most important thing about the fluid simulation is the part you can't see.

Every frame, after the velocity field advects itself forward, the simulation solves a pressure equation and subtracts its gradient from the velocity. This makes the velocity field divergence-free — at every point, the amount of fluid flowing in equals the amount flowing out.

Remove that step and you don't have a fluid. You have an expanding gas.

What divergence-free means

Imagine a small square in the flow field. Fluid enters from the left, exits from the right, enters from below, exits above. The divergence at that point is the net flow out minus the net flow in.

If divergence is positive, more fluid leaves the square than enters it. The square is a source — matter appears from nowhere. If divergence is negative, more fluid enters than leaves. The square is a sink — matter vanishes.

Real water doesn't do either. What flows in must flow out. The divergence is zero everywhere. This is what makes fluid motion look like fluid motion: the curling, swirling, folding behavior that you instinctively recognize. Without it, velocity just diffuses outward like heat.

How the simulation enforces it

The algorithm works backwards from the constraint. After advection, the velocity field has divergence — the self-advection step doesn't preserve it. So the simulation asks: what pressure field, if we subtracted its gradient from the velocity, would make the result divergence-free?

This is a Poisson equation. The pressure is the unknown. The divergence of the current velocity is the source term. Solving it requires iterating across the entire grid — each cell's pressure depends on its neighbors' pressures.

I use Jacobi iteration: start with a guess (the previous frame's pressure, scaled down), then repeatedly replace each cell's pressure with the average of its neighbors minus the local divergence. Thirty iterations per frame. Not exact, but close enough that the eye can't tell the difference.

The expensive part isn't computing what the fluid does. It's computing what the fluid can't do — expand or compress — and correcting for it.

The visual consequence

Drag your mouse across the fluid canvas and watch what happens. The dye doesn't just smear in the direction you dragged. It curls. The leading edge rolls up into a vortex. The trailing edge gets pulled forward. Side lobes form.

All of this comes from the divergence-free constraint. When you push fluid to the right, it can't just pile up — it has to go somewhere. So it flows around the disturbance, creating circulation. The pressure field acts as the messenger: high pressure ahead of the push, low pressure behind, and the resulting gradient redirects flow perpendicular to your drag direction.

This is why stirring a cup of coffee creates a vortex rather than just pushing the coffee forward. The coffee can't compress, so your spoon's forward motion gets redirected into rotation.

Vorticity confinement

There's a second invisible mechanism that makes the simulation look right. Numerical methods diffuse things — that's inherent to computing on a discrete grid. Without correction, vortices smooth out within seconds. The fluid looks sluggish and laminar, like honey instead of water.

Vorticity confinement counteracts this. Each frame, it computes the curl of the velocity field (which measures local rotation), then applies a small force that pushes fluid from low-curl regions toward high-curl regions. Existing vortices get reinforced. New vortices don't get created — but the ones that form naturally from the divergence-free projection get to persist rather than being smeared away by numerical diffusion.

The strength parameter matters enormously. Too low and the fluid is bland. Too high and it explodes — I set it to 15 initially and the entire velocity field went to NaN within seconds as the reinforcement created a positive feedback loop. At 0.35, the balance is right: visible eddies and turbulent structures without numerical instability.

What it doesn't model

This is inviscid 2D flow — no boundaries, no viscosity, no turbulent cascade. Real turbulence involves energy flowing from large scales to small scales until it dissipates as heat. This simulation doesn't have that — the Jacobi solver is too coarse to resolve the small scales where dissipation happens. What it has is an approximation that looks convincing because the visual signature of turbulence (curling, folding, eddy formation) comes from the divergence-free constraint, which this simulation does enforce.

The Navier-Stokes equations that govern real fluid flow are famously unsolved — proving whether smooth solutions always exist is one of the seven Millennium Prize Problems, worth one million dollars. This simulation sidesteps the question by being deliberately approximate. It doesn't solve Navier-Stokes; it solves a simplified version that captures the visual essence while being stable enough to run at 60 frames per second in a browser.

Sometimes the approximation is more interesting than the exact answer.