Fluid Simulation for Dummies

sebg1 pts0 comments

mikeash.com: Fluid Simulation for Dummies

mikeash.com: just this guy, you know?

Home

Book<br>The Complete Friday Q&A, advanced topics in Mac OS X and iOS programming.

Blog

GitHub<br>My GitHub page, containing various open-source libraries for Mac and iOS development, and some miscellaneous projects

Glider Flying

HD Ridge Running Video

List of Landouts

Day in the Life

Skyline Soaring Club

Soaring Society of America

Getting Answers<br>Ten simple points to follow to get good answers on IRC, mailing lists, and other places

Miscellaneous Pages<br>Miscellaneous old, rarely-updated content

mike@mikeash.com<br>E-mail me

Posted at 2006-03-13 00:00 | RSS feed (Full text feed) | Blog Index<br>Next article: Cocoa SIMBL Plugins<br>Previous article: NSOpenGLContext and one-shot<br>Tags: fluid simulation

Fluid Simulation for Dummies<br>by Mike Ash

In the spring and summer of 2005, I wrote my Master's thesis on high-performance real-time 3D fluid simulation and volumetric rendering. The basics of the fluid simulation that I used are straightforward, but I had a very difficult time understanding it. The available reference materials were all very good, but they were a bit too physics-y and math-y for me. Unable to find something geared towards somebody of my mindset, I'd like to write the page I wish I'd had a year ago. With that goal in mind, I'm going to show you how to do simple 3D fluid simulation, step-by-step, with as much emphasis on the actual programming as possible.

The simulation code and ideas that I'm going to present are based on Jos Stam's paper Real-Time Fluid Dynamics for Games. If you want a more in-depth look at what's going on, that's the place to go. You can also read all about how to parallelize the simulation and render the output in 3D in my Master's thesis.

Basics

Fluid simulation is based on the Navier-Stokes equations, which are fundamental, interesting, and difficult to understand without a good background in physics and differential equations. To that end, I'm going to pretty much ignore them except to very briefly explain what they say.

Think of a fluid as a collection of boxes or cells. Each box has various properties, like velocity and density. These boxes interact with their neighbors, affecting their velocity and density. A real-world fluid can be seen as having a huge number of absolutely miniscule boxes, all interacting with their neighbors a zillion times a second.

Of course, a real computer can't handle a zillion interactions per second, nor can it handle a zillion little boxes, so we have to compromise. We'll break the fluid up into a reasonable number of boxes and try to do several interactions per second.

To make things simpler, we're only going to examine incompressible fluid. Air is an example of a compressible fluid; you squish it and it gets smaller. Water is an example of an incompressible fluid; you squish it and it pushes back, and doesn't get any smaller. Incompressible fluids are simpler to simulate because their density and pressure is always constant.

Of course, moving water is really boring if there's nothing in it, because you can't see it moving! So we'll add some dye so we can actually see it moving around. The water is equally dense everywhere, but some of it has more dye than others, and this variation lets us see things moving. So remember, whenever I'm talking about "density", I'm actually talking about the density of the dye, not the density of the fluid. (This took me about six months to figure out, that's why I'm so insistent.)

Data Structures

These boxes will be represented as several 3D arrays. Of course, since C hates multidimensional arrays, we'll use 1D arrays and fake the extra two dimensions. To that end, we have our very first code: a #define which takes three coordinates, and dumps out the corresponding array index in a one-dimensional array:

#define IX(x, y, z) ((x) + (y) * N + (z) * N * N)

Next, let's actually look at how we represent a cube of fluid. We're going to need its size (this code only handles perfect cubes which have the same length on each size), the length of the timestep, the amount of diffusion (how fast stuff spreads out in the fluid), and the viscosity (how thick the fluid is). We also need a density array and three velocity arrays, one for x, y, and z. We also need scratch space for each array so that we can keep old values around while we compute the new ones.

Putting all of this together, we get our fluid cube structure.

struct FluidCube {<br>int size;<br>float dt;<br>float diff;<br>float visc;

float *s;<br>float *density;

float *Vx;<br>float *Vy;<br>float *Vz;

float *Vx0;<br>float *Vy0;<br>float *Vz0;<br>};<br>typedef struct FluidCube FluidCube;

To make sure everything gets set up properly, we need a function that will fill out this whole structure for us:

FluidCube *FluidCubeCreate(int size, int diffusion, int viscosity, float dt)<br>FluidCube *cube = malloc(sizeof(*cube));<br>int N = size;

cube->size = size;<br>cube->dt = dt;<br>cube->diff =...

fluid float simulation density cube size

Related Articles