Flow Fields, Part I
Maybe you’ve heard the term “flow field” and maybe you’ve seen some neat pictures or animations with the term attached. In this article, I’ll cover what a flow field is, show how to create one, and give a few examples of experimenting with them. Flow fields are also known as vector fields. https://en.wikipedia.org/wiki/Vector_field
The Pre-Game Show
I’ll be using HTML5, JavaScript and Canvas for this article, but the concepts will apply to Processing, p5js, WebGL, or just about any other graphics programming platform. That being the case, I’m going to try to focus less on the canvas specific stuff and more on the core concepts.
But, to just lay the foundations, I’m going to go over the files we’re using. It’s all going to be super basic. An HTML file and a JavaScript file. Here’s the HTML:
A bit of CSS, my QuickSettings Panel, which might come in handy eventually, a canvas element and a link to the main script. The script is going to start out like this:
All we’re doing here is getting a reference to the canvas and its context, then resizing the canvas so it fills the browser window, saving the width and height values for later use. Some of the CSS in the HTML file aids in all this being fully possible.
The Main Event: Flow Fields
So, what is a flow field? Well, you can think of a field as just a two-dimensional area. Of course, you could have a 3D flow field, but let’s save that for another day. You can also think of a magnetic field.
In this image of iron filings revealing a magnetic field, you see various lines and loops. The strength and orientation of the magnetic force is different in different areas of the field. You can imagine that an object moving through this field would be influenced by it and tend to move along those visible lines.
Basically, that’s what we want to do — create a two-dimensional area where each point has a different value. But these aren’t just random values. A particular point has a particular value and as you move out from that point to neighboring points, you get similar, but gradually changing values. In flow fields, these values are usually interpreted as directions. So if you map your values so they are between 0 and 360, they can be directly used as degrees of direction. Of course, we’ll probably map them between 0 and 2 PI radians because the computer likes that better.
Once we have values for each point, we can graphically render each one based on it value. For example, we can draw a line pointing in the direction associated with that value.
So that brings us to two different tasks — how to come up with the different values for the field, and how to render the different values on the field. The great thing is, there are no correct answers for either one of those questions. In fact, there are nearly infinite ways of doing either one, so you can explore this technique for quite a while.
Let’s start out really simple, to get the idea of what’s going on. I’m just going to loop through from left to right and top to bottom, every 10 pixels. The value for that point on the grid will simply be (x + y) * 0.01 % Math.PI * 2
. Just adding x and y together, scaling it down and modding it by 360 degrees (PI * 2 radians). Then we render that value by translating to that point, rotating by the value and drawing a short line at the point.
Simple as that all is, we already have the start of something interesting going on.
You might now see why this is starting to be something you’d call a “flow field”. As you follow the directions of the lines, you start to see some very directional motion going on.
We can start cleaning this up a bit by extracting the two things that we’ve already determined are going to change a lot — the calculation of the value and how each value point is rendered. We’ll put each one of those into its own function and call them where appropriate.
No change in behavior, but we’ve isolated the things that we now want to change. Furthermore, we don’t necessarily always want this to be in a strict grid. Instead we can grab any number of random points on the grid and render those.
I’ve arbitrarily defined a value of 20,000 for number of points to render. Just looping through that many times, getting a random point and finding its value and rendering it. I’ve changed a few other values as well, such as the length of the line and the scale value that (x + y) is multiplied by. Now we’re getting something a bit more natural looking.
At this point, we can just start messing with the formula we use to get the value. Generally, you’re going to want to use the x and y inputs somehow, but really, just do whatever you want here. Here’s a somewhat interesting one I came up with.
Just taking the sine of x and y and adding them together. Some rendering changes too: reduced the line width and varied the line length at each point. But with just those few small changes, we’re onto something really hairy looking.
Now I could spend all day iterating on this — different formulas, different parameters for the lines it’s drawing etc. I know I could spend all day on it because I have spent whole days doing just that in the past. But let’s move on to something else.
Earlier I mentioned the idea that you could possibly imagine an object moving through a flow field and being influenced by those flows. Let’s simulate that. I’ll start with a single random point. Call it a particle. This particle will actually be an object with not only position, but velocity on the x and y axes. Initially these will be set to zero. On each iteration, wherever the particle is, we’ll get the value at that location — which is a direction, remember — and use that value to influence the particle’s velocity. Then we’ll add that velocity to the position to get a new position. And repeat.
Hopefully the comments explain a bit more what’s going on here. This gives us the following:
What’s interesting in this case is that we no longer actually see the field. We only see the result that the field has on the motion of the particle.
Do run this one on your own. It’s pretty neat to watch the drawing build up over time. You can see that the flow field is influencing the way the particle moves. You can change some of those hard-coded values to see what they do to the motion. Even in just our fifth iteration here, we have a ton of things to experiment with.
Let’s do one more for this article. Where one particle was fun, more particles is… more fun.
Here, I just made an array of particles and arranged them down the left side of the screen. For the algorithm, I used a strange attractor called the “Clifford Attractor”, published by Paul Bourke and attributed to Clifford Pickover. You can see the code for that here: http://paulbourke.net/fractals/clifford/ This gives you a very complex field. The parameters, a-d, are randomized at the top of the file, so you’ll get a different pattern every time.
Again, this is one you want to run on your own and play around with. It’s really quite beautiful to see in action. If you’re curious what the flow field actually looks like for one of these attractors, it’s something like this:
OK, that’s enough for one article. In part two, we’ll look at some other ways to create fields and other ways to render them. If you want to play around with the code itself, you can either grab the gists I’ve embedded here, or just check out the full tutorial repo itself at https://github.com/bit101/tutorials
Also, if you’re looking for other such quality coding tutorials, check out my main site at http://www.bit-101.com