Creating Art with Code: Perlin Noise and Flow Fields
I've always been fascinated by the idea of creating connections between my interests. I find a great sense of joy in being able to notice and form connections between things that might at the surface seem unrelated. And while I will not act like art and mathematics weren't already connected time and time again throughout history, getting to actually apply and then experience it first hand was one of the reasons I started blogging, actually. I've been waiting to share this with the world for a looong time. Hopefully by the end of this blog, you'll know how visuals like this blog's cover were generated, and you'll have access to the tools I used to generate it to test out directly.
What is a Flow Field?
Okay enough being vague, I'm here to talk about flow fields.
A flow field in short is a group of vectors in a grid that tells the items closest to them how to move or act. A balloon floating at the beach, for example, can be seen in terms of flow fields, since the sea has many different acting wave motions that push the balloon around at its surface. Though in reality, it's the other way around. Flow fields are actually used to simulate real life fluid dynamics, so it's more like the flow field is imitating the sea and not the other way around.
In this field, for example, all points in the grid point in the same direction.
A grid like this isn't very challenging to make, but it's also not very interesting since any particles we introduce will just move in a straight line. To start modifying this grid, we'll have to pass each point's position through a function that will return a value for our force at that point, for example
passing all our points through a function like this allows us to point all our vectors towards a point, here's what that looks like when we tell it to target the center.
Now to actually add some moving particles
First we need to generate our particles and add them to a list that we can access later. Then on every movement frame we need to:
- Find the nearest vector to our particle
- Add their value to our particle's speed (simulating the vectors pushing the particle)
- Normalize this new speed so our particles don't go flying off
- Actually move the particle to their new position after the applied speed
- Draw a line between the old position and new position
- Make sure our particles aren't lost if they go outside our window
Here's the code for how I did that:
and now, by calling the move function every frame, as well as some visual flare, we have this:
click the black box to start/unpause it
They'll keep moving until they all reach an equilibrium where they're spinning around the center, never really reaching it. Quite curious isn't it?
Interestingly this behavior is caused by how our particles never lose or gain speed, they always move with a stable velocity, leading them to this form of circular motion
Now that we have a flow field
We can start testing out different flow field configurations. What if the flow field started following the mouse? Or how about if we made the center point PUSH instead of pull in particles?
But the one I find most interesting is, what if we made the vectors all random?
click the black box to start/unpause it
Interesting visual, but still, there's better, this is where I finally bring up Perlin noise
Perlin noise?
Perlin noise is a type of noise developed by Ken Perlin in 1983. He wanted to create a noise algorithm that wasn't so "machine-like."
Perlin Noise | Static Noise |
---|---|
![]() | ![]() |
It's meant to simulate more natural patterns, where each random point affects those around it, and we can use it as a basis for our vectors.
Using an external library to generate our noise2D based on x and y, it returns a number between [-1, 1]. So through some trigonometry, we can turn that number into an angle from [-π, π] giving us the full range of a circle and slotting it in to get an x and y which are already normalized, how convenient.
click the black box to start/unpause it
And if we leave the domain of 2D, we could actually generate a 3D Perlin noise map and travel through that third dimension over time
Isn't it beautiful?
don't click the black box!!
Finally,
If you're interested in trying this out on your own, feel free to take a look at the Related Lab Entry
and if you really want to, you can look at my messy code here, but let me warn you... I was rushing already rushed code, so it's not the cleanest
Updated JSX version
Old static JS version