Playground
Fluid (Stable Fluids)

Incompressible fluid on the GPU

Stable Fluids Jos Stam described a fluid solver in 1999 that never blows up, even with large time steps. Each step moves the fluid along its own velocity and then makes it incompressible. Paper: Jos Stam (Stable Fluids)

Navier-Stokes equations The equations describe how velocity and pressure of a fluid change over time. This demo solves a simple form without viscosity. Read more: Wikipedia

Fluid on the GPU Velocity, pressure and dye are float textures. Every step is a fragment shader pass over all cells at once, and the textures swap roles after each pass. See GPU Gems, chapter 38: GPU Gems, chapter 38

Original work

How it works

Every frame runs these passes: add splats, vorticity, pressure projection, advection.

  • Splat: a gaussian blob is added to the velocity (the drag direction) and to the dye (the current color). The color hue changes slowly over time.
  • Vorticity: the curl of the velocity is computed, and a small force along its gradient keeps small swirls alive on this coarse grid.
  • Pressure: the divergence of the velocity is computed. Jacobi iterations solve the pressure from it. The slider sets the number of iterations. More iterations make the fluid more incompressible and cost more time.
  • Projection: the pressure gradient is subtracted from the velocity. What is left has no divergence, so no dye piles up or vanishes.
  • Advection: every cell looks back along the velocity and takes the blended value from there. This is done for the dye and for the velocity itself. Both fade a little each second.

Source code:fluid.shader.tsfluid-simulation.tsfluid.model.ts

Note Simplifications in this demo:

  • The velocity grid is 128 × 128, the dye grid 512 × 512. The time step is fixed, so the fluid runs slower than real time when the frame rate is below 60.
  • The walls are solid with free slip: the fluid cannot leave the field but slides along the edges. There is no real viscosity, only a damping of the velocity.
  • If the GPU has no float32 render textures, float16 is used. Very faint dye then vanishes faster.
Velocity damping
Dye fade
Pressure iterations
Force
Splat radius

Press and hold the mouse or a finger on the canvas and drag to push the fluid and add colored dye. If you do nothing for a few seconds, the simulation adds a splat by itself.

Frames/s: 0Backend: –Grid: 128 × 128 / 512 × 512Pressure iterations: 20