Fluid simulation is vastly useful in all sorts of digital areas.
Many of our most beloved films contain 3D fluid simulators to help render gases, smoke, water
-and its reflections.
In games, fluid simulators are used for much of the same, but also for simulating physics of different mechanics.
This project works to show that fluid simulation is no longer an obstacle, and can work with varying degrees of quality even on a poor computer.
2. Navier-Stokes equations
3. Computation & Code
5. Discussion and Conclusions
A huge amount of the fluid simulators that are around today are based on Jos Stams papers on "Stable fluids", and "Real-time Fluid Dynaimcs for Games. The purpose of those articles were to prove that a fluid simulator need not be a huge obstacle, as many thought at the time. The computational view for a fluid simulator were horrendous - It seemed that we had to solve many enormous arrays to get a realistic fluid, but the proof of concept in Jos Stams papers proved that this neednt be, and as this small project shows that fluid simulation isnt a very large obstacle anymore. The fluid simulator used in this project is poorly optimized, run over a console on a lower/medium range computer, and yet it still works responsively. Many problems and faults were encountered on the way, and not all were solved. The results presented here should be taken lightly.
The main solution method for the simulator in this project is to iteratively and numerically solve the
Navier-Stokes equations for fluid motion:
A real fluid is very complicated, but the motions of fluids are not beyond comprehension. When seen from above, the surface density of water looks very much like the movement of 2D gas in a box. And this is exactly what makes this fluid simulator so useful. Without gravity, the fluid will behave much the same as a gas. This is useful for graphical analysis of both water and gas.
A fluid can be viewved as a distribution function with discrete points - that is - we can write a body of fluid as a collection fields:
p - This is the scalar field containing at each point the density of the fluid. This field will diffuse over time, in the real world this is governed by statistical diffusion through Brownian motion. In the code, however, we must diffuse “manually” by linearly solving where the distribution will be in the future. This is also the field which governs the colour intensity in the GUI.
u & v - These are the vector fields containing at each point the velocity of that point in the relevant direction. u for horizontal (x) movement, and v for the vertical (y) movement. These vectors can also be rendered into the GUI, but by other methods (discussed below).
Some aspects of the fluid are worth mentioning, as they are the visually apparent mechanisms, and the defining mechanisms for this simulator. The pressure diffuses based on the viscosity of the fluid. The higher the viscosity, the less the fluid will flow. Water has a viscosity of around 0.4 mPa*s, air has a value of 18.5 micro Pa*s, and honey has a viscosity around 2000-10000 mPa*s. In this project, the viscosity of water is used, as this is the fluid most people are " intuitive " with.
The velocity field also diffuses, as the fluid must distribute the pressures. Some other mechanisms we need to know about are mass conservation(projection), and dye movement due to the velocity field(advection). These mechanisms are represented by the functions presented below.
The program consists of the basic mathematics functions for the fluid itself. These methods were studied
through several different implementations of different fluid simulators, and engineered(unsuccessfully) for c++ with root.
This was not an easy task, and is not completely finished yet. Alas, the program is presented here.
(source code: folk.uib.no/sen006/sen.C)
The fluid itself is set up as a class containing several fields, and the mathematical functions which solve for the
future state of the system. The fields used are the pressure field, and the two vector
fields for the velocities. Since we are iteratively calculating the next state of the fields, we need the
old states of all the fields, pField_old, uField_old, and vField_old as well.
Diffuse - This algorithm is what makes sure that the pressure field diffuses into its neighbours. In a fluid, there will always be counter balancing for high pressure areas - the pressure diffuses from high to low pressure, trying to reach equilibrium pressure. The diffusion algorithm works by solving a linear differential equation for the state of the system after a certain timestep dT. A good metaphor for this would be to imagening pouring dye, or soy sauce into a body of water and watching the colour diffuse.
Linear solve - This is the algorithm which iteratively solves a system of linear differential equations. This system is used by both the diffusion algorithm, and the projection algorithm.
Advect - The velocity field will cause the dye in the pressure field to move in the direction of the fluid movement, in other words - it moves the dye through the fluid.
Project - This algorithm makes sure that the mass is conserved. This is done by iteratively solving the system a differential equations for the positions of the pressure field, and making sure that the total sum is always the same.
setBounds - This function lets us have a contained liquid, instead of one that leaks through the edges of the simulator. It works by setting the velocity at each edge point to the same value as the point adjacent to the edge point. For the liquid, the edge then will seem like a solid edge.