Vorticity Confinement - sahilshahpatel/fluid-sim GitHub Wiki

You're almost done! This is the last main series chapter. In this chapter we will be implementing vorticity confinement.

Our previous techniques for advection, diffusion, and projection are great because they are stable, which means that no matter the time step they will get a reasonable result. However, these methods do have downsides. One important downside is that they reduce the vorticity (think whirlpools or swirls) of our fluid. We can combat this to some extent by adding a restoring force.

This chapter's contents are not a part of Jos Stam's original algorithm. Please use the NVIDIA GPU Gems chapter or the Fedkiw et. al. followup paper as external resources.

Section 1: The intuition

The first thing to recognize is that vorticity is simply a term to describe the curl of the velocity vector field. Since we are exclusively talking about the velocity field here, we'll use the terms pretty interchangeably.

Ideally the fluid within a single cell would curl or spin based on that cell's vorticity. In practice, of course, the full cell must have the same velocity, so we cannot have the top go one way and the bottom another to generate that spin.

What we do instead is generate a gradient for the vorticity. This will give us a vector for each cell pointing toward an area with higher vorticity. With this vector we can allow high-vorticity cells to influence their surroundings, in a way, while still remaining entirely parallel.

Let's look at an example. In the image below we can see that the center is the area of largest curl. All around that central vertex the curl is the same direction, but the magnitude is less as you move outward.

Large counter-clockwise flow field

By the right-hand rule we know that the curl vectors are all pointing out of the screen (towards you). If we cross that vector with the vector pointing towards the center (the area of higher curl), the resulting vector points in the direction we expect the fluid to flow! This works for points in any direction from the center point.

Same flow field with vectors drawn on

This works the same way if you have multiple vortex sources. The gradient operation will select the dominant vortex affecting that cell, and the cross product will tell us how to move in order to follow that vortex flow.

Section 2: The math

So we have some understanding of what we need to do. Now let's formalize it.

Our algorithm has four steps:

  1. Calculate the vorticity \omega = \nabla \times v
  2. Calculate the vorticity gradient \eta = \nabla \vert \omega \vert
  3. Normalize the vorticity gradient \psi = \eta / \vert \eta \vert. We do this so that the vorticity gradient gives us the correct direction without influencing the magnitude of our force.
  4. Calculate the confinement force f = \epsilon (\psi \times \omega)

Section 3: Implementation

You can add this restorative force alongside our other user-generated force in addForces.glsl or in a separate shader. For performance reasons, fewer shaders is ideal, but for organizational reasons you may wish to keep them separate.

What's next?

You've reached the end of the tutorial! The next chapter gives you a few suggestions for how you might extend your implementation. If that interests you, check it out!