[MUSIC PLAYING]
Good morning.
Welcome to Coding in the Cabana.
I'm here with my co-host, Gloria Pickle.
And today the topic is Worley noise.
Now I'm particularly excited about this topic.
I'm here, quarantined at home, like many of you
are who might be watching this all around the world.
And I did a live stream where I implemented Worley noise.
So I've done this before, but I had some technical difficulties
and so I wanted to come back and make a really short video where
I just coded the algorithm, explained it, and put up a web
page so that you could share your own versions
of this kind of noise.
The noise is nothing new on this channel.
I have covered all sorts of kind of noise.
Perlin noise being the most--
the noise algorithm that I use the most, probably.
Now anytime I'm doing a noise algorithm,
we've got to talk about how am I visualizing.
I want to visualize this algorithm,
and I want to look at the noise in a two-dimensional space.
So I'm going to start with a Processing window,
and I just want to set every single pixel color to a noise
value.
Now just plain old noise is randomness.
So let's set up, and let's just do plain old noise first.
In order to set every single pixel of this window
to a given color, I need a nested loop
to look at every single x and every single y.
Now the pixels are stored in an array, and I can access it.
It's just a global variable in processing
that's built in with just the keyword pixels.
But I don't know where exactly I need to look at.
I'll get to that in a second.
So I want to set every sing one of these pixels
to a given color.
Let's make it, just to start with, some kind of pink color.
So what goes in here?
So if I have a two-dimensional window, that's, let's say,
it's 400 by 400.
And let's scale that down to 4 by 4.
Every single pixel has an index.
There's a number associated with it.
0, 1, 2, 3, 4, 5, 6, 7.
There's 16 pixels total.
4 times 4 is 16, and their index values go from 0 to 15.
You'll notice that 2 plus 4 is 6 plus 4 is 10, or 0 plus 4
is 4 plus 4 is 8.
So this width, four is the offset between the index values
in any given row.
So there's a really nice formula that I can use,
which is actually just take which row am I on,
multiply it by 4, and add that to the column.
So if I'm on row 0, 1, 2 times 4 is 8 plus the column 1.
1 plus 8 is 9.
Or in other words, putting this in code,
int index equals x plus y times width.
That's the formula.
Look at the index.
So this would set the entire window to pink.
Now if I run this, it's going to tell me,
I have no idea what you're talking about.
Because Pickle, what did I forget?
Exactly.
That's right.
Pickle knows, and one more step.
I've got to tell it I'm done with it
so it can render those pixels.
Birds are really chirping today.
What a lovely day it is.
There we go.
There's my nice little pink beautiful window that I love.
So let's change this to a noise algorithm,
and pure noise is randomness.
We've got this old-timey-- the television has no signal,
and I know that you watching this
are watching this on your tubular, old-timey television.
Worley noise is a kind of cellular noise,
and the algorithm was proposed by Steven Worley
in a paper published in 1996.
There's a really basic, two-step process
for generating the noise.
First step is randomly distribute feature points
in space.
So what do I mean by that?
I have my two-dimensional space.
I'm actually going to make it three-dimensional in a moment,
but let's start with just two dimensions.
And I need to randomly distribute a bunch of points.
So how many points did I put here?
Seven.
Let's start with seven points.
Easiest way for me to create seven points
is just make an array of p vector objects
and give it seven total spots.
And then initialize every single one of those points
with a random place in the canvas.
Now one of the things that you could
do if you're making your own version of this
is think about, well, how do you actually generate those points?
Maybe they're the points along the path
of some other kind of design or have some other algorithm
to distribute them.
But I'm just going to let them be totally random.
Let's take a look at those points
by writing another loop down here.
This is a special kind of loop that looks at every object v
inside of the array points.
And I'm just going to actually literally draw it as a point.
Let's give it a stroke.
Let's make it green so I can really see it and give it
a kind of larger stroke weight.
And there we go.
So now we see every time I run this,
I'm going to get a new set of points.
So step 1 is done.
Randomly distribute feature points in space.
Step 2 is really where the noise algorithm starts to kick in.
f of n of x.
So x being the given pixel, xy.
So for every given pixel xy, I need
to calculate a noise value.
And it is equal to the distance to the nth closest point,
meaning let's start with n equals 1.
So if these are all my seed points,
and then I happen to be looking at a given pixel,
for example, this pixel, which point is the nth closest?
The n being 1, the first closest.
That's this one.
If I were looking at, let's say, n equals 2,
well, let's say this is the second closest.
Now you might start to think, wait, this kind of reminds me
of something.
Let's just look at three points.
I can kind of create this tiling where all the points here
are all closest to this one.
And all of the points here are all closest to this one.
This is known as a Voronoi tessellation.
And this is a--
Worley noise and the Voronoi tessellation
are completely interrelated.
I'm actually in many ways doing the same algorithm.
Worley noise is going to veer off into a different direction,
but this is something I should come back and revisit.
How can I look at this particular problem
from a computational geometry perspective?
In the case of Worley noise, we're
just going to look at every single pixel and its distance
to the closest feature point.
Every single point, and calculate
the distance between the xy and that point's xy.
And let's put all those into an array of distance values.
The reason why I want to look at all the distances
is because I want to vary this n value.
Sometimes I want to look at the first closest,
second closest, third closest.
Maybe I don't need them all, but let's just
keep them all right now, store them all into this array,
and then after that, I can sort the array.
That's an array also.
So I could write my own algorithm for sorting an array,
but processing has it built in.
If it's just an array of numbers,
processing will sort it for me, just with the sort function.
And let's ask the question of what n do I want to use,
if I want to use n equals 1.
Then the color-- it's not going to be a random value--
that noise value is front distances n of 1.
And actually, so n should be 0, because 0 is
the first element of the array.
And I'm going to set it to a color.
Ah, not the distances.
I want the sorted ones.
The distances were sorted, so the closest one is always
at the beginning of the array.
There we go.
We can start to see this Voronoi-like tessellation.
Let's do a little bit of a mapping.
Let's say the distances range between 0
and width divided by 2.
And when it's really close, when the distance is 0,
I want it to be very bright.
And when it's far away, I want it to be dark.
There we go.
This looks more like what I would expect.
And interestingly enough, we can do some fun things,
like we can have these points move around.
Them shaking like this perhaps isn't the most interesting
movement, and maybe having them be bouncing balls bouncing off
the edges or flocking together or moving in spiral patterns
or with Perlin noise, I'll let you explore that.
Maybe I'll come back to it later.
But you can see that these points can actually
move around to create an animation out of the noise.
Let's look at what happens when I have a lot more points.
So instead of 7, let's try 25.
And there.
We see the same sort of thing.
We see the same pattern, but the cells,
the cellular texture of it, their cells
are getting smaller and smaller.
100.
Because there are so many points now,
it's not having an easy time calculating the distance
to all those points.
And it's running quite slow.
So this is where I want--
I would want to add some kind of optimization to it,
but I'm not going to worry about that right now.
I just want to compute static noise,
and doesn't matter if it takes a long time.
So I'm going to get rid of this idea of an animation.
I'm actually, in fact, let's just
comment out drawing the points entirely,
and let's write no loop here.
So there we go.
So I can see here is a very basic visualization of Worley
noise.
It looks quite like the example here on the Wikipedia page.
Obviously, that page has it darker closer.
So if I changed it to this, and I'm not
getting that full brightness, because the points
are also close.
Let's just manually come up with a range here.
There we go.
I have now created basically exactly what
is on this Wikipedia page right here.
Now remember, the idea of Worley noise
is that I have this additional variable n,
so I don't just have to map the noise
to the distance of the closest point, which will give me
the Voronoi-like pattern.
I could also calculate the noise value
based on the distance to the second-closest point,
in which case an n of 1.
And look at this.
I have this almost more like crystal-like structure to it.
What happens if I change it to n of 2?
n of 3?
Change the mapping to allow for a larger range of distance.
So you can see, there's lots of different kinds of textures
that you could generate, based on how
you manipulate that mapping, how many seed points do you pick,
as well as which value of n you're using.
But I have missed something.
So Worley noise, even though we're
looking at this sort of two-dimensional visualization
of it, those feature points could actually
exist in three dimensions.
So I could think of a cube in three dimensions,
pick a whole set of initial feature points,
and then look at a slice inside of that cube.
To do that, let's add a z value to the p vectors.
I'm keeping everything in square dimensions,
because I think it makes things a little bit simpler here.
So it really actually doesn't matter
that I have a width and height.
Everything is 400.
So let's keep the z values also between 0 and 400.
I'll just use width arbitrarily there.
This distance is no longer between an x and y and an x
and y.
It's between an x, y, z, and an x, y, z.
And just to make this read a little bit easier,
Let's put the particular point that I'm
looking at in a variable v. And let's also add a z.
So now I'm looking at the distance between two points
in three-dimensional space.
I have my feature points, the x, y, and z of the given feature
point, and then the x, y, z of the given pixel I'm looking at.
But again, I'm looking at a slice.
So z is constant.
So I'm going to make up a z value.
Let's just look at the center slice, width divided by 2.
And let's change n back to 0.
So I look at the closest point and see what this looks like.
Not too different, right?
Can I quickly see the difference?
I'm going to just say if mouse pressed d equals--
let's just look at that 2D distance.
Let's allow it to animate.
So you can see here, when I click the mouse,
there's a lot more cells.
Let's see if I use fewer feature points,
if this is maybe a bit more obvious.
So that, the 3D--
that's with the feature points in 3D, and this is within 2D.
So we can see there's a bit more of a spherical kind of quality
to them.
It's a bit smoother, the noise texture.
Let's go back to about 50 points.
Let's stick with 3D.
Let's look at n equals 1.
n equals 3.
Now something that I could try that's pretty interesting
here is I could vary the z.
So for example, I could look through
what does the noise space look like at any given
different slice?
So what if I had z just be frame count modulus width.
So at every frame of animation, I'm
looking at a different slice.
When it gets to the top slice, it goes all the way back down.
Let's set n at back to 0.
You can see it slowly animating.
It's as if I'm scanning into this three-dimensional space.
One thing I could try here, just to add a little more flair
to this, is I could use a different n for an RGB color.
So I could have the red value be tied
to n equals 0, the green to n equals 1, and the blue to n
equals 2.
Let's see what happens there.
So let's actually call this r is sorted 0.
g is sorted 1 map.
And b is sorted 2.
And then the color is RGB.
I could also play around with varying the ranges,
and I could have this go to 55 down to 0.
And maybe the blue value, change this to 200.
A lot of possible kinds of colors and textures
I could create just from varying the
how I map the ranges, which distance I use.
But here we go.
We can see this is basically the foundation upon which
you could create your own animation
or texture with Worley noise.
So what might you want to try with this?
A couple things.
One is this is running pretty slow.
I'm able to get this.
It's a reasonable frame rate of 400 by 400,
but this would really merit some optimization.
One optimization would be to improve
on how many points you need to look at for every given pixel.
So you don't need to actually look at all the feature
points for every given pixel.
We can register the points into given cells into the window
and only look at a few of them, and I've
covered this topic extensively in my quadtree videos.
But you could even use a sort simpler,
just like spatial subdivision without the quadtree whole
thing itself.
Otherwise, just the rendering is quite slow,
having to do this calculation for every single pixel.
There's a really nice resource called The Book of Shaders,
and it has a tutorial write-up about how to compute Worley
noise with a web GL shader.
It's called The Book of Shaders.
So I'll link to that in the video description as well.
So I look forward to your own versions of Worley noise.
I'm going to leave you with a rendering
that I made during the Livestream.
When I first coded the Worley noise algorithm,
it didn't-- this run originally in real time.
It's 1920 by 1080.
Computing the noise space in that with that resolution,
but using saveFrame in processing
was pretty easy to render out every single frame
and just let it run, save it, and export it to a movie.
So I'll link to the time code in the video description
where I created this.
I hope you enjoyed this delightful day of coding
Worley noise in the cabana.
I'm going to go outside play with Pickle a little bit
and water the plants.
Come on, Pickle.
[MUSIC PLAYING]