Tap and drag to add turbulence to the simulation.
Wikipeida says that the Navier-Stokes equation is
where
is density
is the velocity vector
is the pressure
is the stress tensor
is any other acceleration
is the gradient, equal to
for however many dimensions. This simulation is only 2 dimensional so in this case it is just
.
is the divergence and is the dot product of the gradient with the vector so it is equal to to
for however many dimensions. In 2 dimentions it's
.
is the material derivative which is
, which measures how much material will change measured at a point moving with the fluid.
Here it is taking the matieral derivative of the velocity, or saying how much a particles velocity will change as it flows through the fluid.
so the origional equation becomes
doesn't matter here since it is the stress tensor used for viscosity and when the shape of the box is changing size and volume, but both of those are ignored, and we can also don't have any external forces like gravity or electromagnetism so we can ignore
.
Then expanding the vector
Applying the finite distance method:
onto
makes:
Then isolate :
The first 3 terms are just the advected velocity, because its equal to
. Make a new variable
for the first 3 terms, the advected velocity.
In incompressable fluids, density is constant so
is a constant. If
is constant then
so the conservation of mass equation:
becomes
and since
is a constant it can be divided out
One point can't have 2 neighboring points both pulling from it or else that means it is going in 2 directions and creating new mass, or if a cell has 2 neighbors going into it mass is deleted since density can't change, so the divergence of the velocity at every point must equal zero.
So the solution must also have zero divergence
Then also apply the finite difference method
We can substitute the previous equation for the 2 derivatives.
Then move the knows and unknowns to the left and right sides.
Then simplify
In the code this systems of equations could be solved with a massive matrix with each voxel as a variable and have very perfect calculations, or just do it iteratevly and approximate with an iterative solver. This code uses the
Gauss Seidel method. Set
to the left hand side of the equation.
And with that system of equations iterate by setting the initial guess for every point
. Then iterate with
After the divergence is cleared, the velocities just need to move both the color, themselves, and any other values in the direction they are pointing.
In code this is optimised by pulling instead from behind instead of pushing out in front because the end point of the velicity will be inbetween 4 squares and writing values is almost always more expensive than reading values, so instead it will read the 4 values of the squares if the velocity vector was rotated 180 degrees or muliplied by -1, linear interpolate the expected value at the sub-voxel position, then write it into only one square saving time and making the simulation faster at about the same accuracy as the intuitive method.
Now the hardest part is done, but there is still diffusion where quares take the average values of their neighbors over time this is modeled by
between the new and the current attrubute,
and the percent it goes towards it in that time tick,
this is again a system of equations that can easily be solved with the Gauss-Seidel method
For boundaries and walls, the velocity in that voxel must be both 0 in the y and x direction, so when divergence clearing is calculated it will make the velocity near only be able to flow parrallel to obsticles and the boundary. Since the divergence clearing isn't perfect it doesn't make velocity exacly parralel so some fluid leaks off the edge or into walls, so a script should iterate through every voxel and make the x velocity 0 if there are obstacles or boundaries to the left or right, and y velocity 0 if there are up or down, exept a more computationally efficient way is to just set the voxels which are considered boundaries to have a x and y velocity of 0, then the divergence clearing will automatically make flow parralel to them
For the numerical implementation of derivatives it is just
which can also be
then to
and in code form with the voxels where the position must be integers the most accurate would be would be
used sources:
https://jamie-wong.com/2016/08/05/webgl-fluid-simulation/