I’m writing this blog-post because during my google research, I couldn’t find any hits that helped me achieve fluid like warping of textures - similar to what you’d get by running a Navier-Stokes fluid simulation.
If you’re unfamiliar with fluid simulation, Jamie Wong gives a pretty good rundown of it on his blog. You can open that page and see a fluid sim right away, and even use your mouse to influence it.
My goal here is to use Substance Designer to create an easy-to-use node that gives us those curly vortex shapes that happen naturally in these fluid simulations. Unfortunately, the current off-the shelf tools that come with Substance Designer don’t give you the ability to get those nice vortex shapes without some setup. You’re able to warp images, but they often end up pinching or stretching in ways that don’t look like fluid at all.
Typical result of using Vector Morph derived from a Gaussian noise. Notice the pinching and stretching that happens due to divergence in the vector field.
At first, I tried recreating the Navier-Stokes equation directly inside Substance Designer and succeeded (sort of), but the node was just too cumbersome since there’s many calculations that need to be done on several components of the simulation’s equation in order for it to look correct. Each calculation of the equation is just one time step, and you’ll need several hundred steps to get a result that’s acceptable. This approach ended up being completely impractical, however it wasn’t a total failure because I came away with the knowledge to achieve what I needed to in a much simpler way.
Before i get into that, i want to spend a moment to talk about what makes a good fluid simulation. This is a long walk, so bear with me. The key is having a non-divergent vector field to advect your texture with. Divergence, in this context, is the measure of how much fluid enters or leaves a given area in a single time step. If more fluid enters than leaves, it has positive divergence, which will eventually lead to pinching. If more fluid leaves than enters, it has a negative divergence, which leads to nasty stretching. A field that has no divergence has the same amount of fluid entering and leaving any given area which leads to a beautiful warping effect with no pinching or stretching. Unfortunately, as I explored the solutions offered to me in Jamie Wong’s post, I realized that creating a divergent free field is easier said than done. Doing so requires calculating pressure from divergence and then using like, 40 - 80 Poisson blurs to generate a nice enough pressure gradient that is then used to create ANOTHER vector field which is subtracted by the previous time step’s velocity field after it has been advected by itself, etc. It gets pretty complicated, but the end goal is to create a non-divergent vector field so that we get those pretty swirly shapes.
In order to cut down on complexity, we can take a step back and think about what’s necessary for us to achieve our end goal. Lets assume that we don’t care about several fluid properties like viscosity or diffusion rate or density for the time being. We also don’t care about variable force, because at the end of the day, we’re not running a simulation, we’re creating a single node that gives us results SIMILAR to a simulation. With that being said, we can just make the assumption that we’ll be using a constant vector field which does not change over time to drive our warping effect. With that assumption, we can just precompute a single vector field, and as long as that vector field is as non-divergent, we’ll get acceptable results.
But… how can I generate a divergent free vector field in Substance Designer? The answer is simpler than you’d think. We use a grayscale height field and calculate it’s curl to create a “Curl Field”. We do this because a Curl Field has the property of being divergent free! Unfortunately, there are no prepackaged tools that creates a Curl Field from a Height Field, but making one is incredibly easy to do, especially if you’re working with a two dimensional vector field.
The set up is easy. Grab a smooth grayscale noise like Perlin noise or Gaussian noise. Convert that into a normal map using Height-To-Normal World Units. (this gives a normal map with a nice range). Then use the Normal Vector Rotation node to rotate your normals by -90 or 90 degrees. That’s it. This creates a vector field where, instead of the vectors moving along the slope, it curls AROUND the slope, hence the name “Curl”.
The same Vector Warp as above, but this time it’s being advected by a Curl Field instead.
An advantage to this setup is that you can experiment with other weird noise patterns. You can essentially use an HQ Blur on any height field and use the results to generate something usable! Here’s some more examples of some cool shapes.
This should be all you need to get started playing around with creating and using Curl Fields! My next blog post will cover an expansion of this where we use Curl Fields to create a fast “Fluid Morph” node that takes viscosity and diffusion into account. Stay tuned.