I wanted to mess around with fractional
sums of Perlin noise, so made a little openFrameworks app to better understand
what is going on.
Frequency
Frequency comes up quite a bit in the following discussion, and more or less means the rate at which something goes up and down. All you really need to keep in mind is:
High frequency noise goes up and down
quickly. It looks like this (where black is 0 and white is 1):
Low frequency noise goes up and down
slowly. It looks like this:
You can see low frequency noise takes a while to get from zero to one and vice versa, while high frequency noise does it much more often.
ofNoise Inputs and Outputs
In general it’s a good starting point to pass normalized coordinates to the noise function.
You can use ofNoise() to get values ranging
from [0, 1], or ofSignedNoise() to get values from [-1, 1].
There are a bunch of functions for various
dimensions as well.
Fractional Sums
Low frequency noise will give a nice undulating look, but often it is boring. High frequency noise is more interesting, but can be a bit too chaotic. What we want is a nice combination of both.
Using an example from Paul Bourke, we take
several instances of noise at increasing frequency and combine them to get the
effect we are after.
To do this there are three parameters, an
octave count, alpha, and beta.
The octave count is how many layers of
noise we will be adding together. This will typically range from 1 to 8.
Each layer of noise is generated at a
higher frequency than the one before, which is where the name octave comes
from.
Beta controls the frequency of noise, the
larger it is, the higher the frequency of the noise, i.e. the faster it goes up
and down.
Adding these together works, but you might
find the higher frequency noise overpowers the lower frequency noise.
This is where the third parameter, alpha,
comes in, controlling how much of the noise from the current octave ends up in
the final sum.
In rough code it looks like this:
double sum = 0.0; for (int n = 0; n < octaveCount; n++) sum += 1/alpha^n * noise(n * beta * x, n * beta * y);
Lets say alpha and beta are both 2. In the
call to noise(), the n * beta term will get progressively larger for each
successive layer of noise. We are increasing the frequency of the generated
noise.
However, with alpha as 2, we are adding
successively less of each octave, as we get 1/2, 1/4, 1/8, 1/16 … reducing the
magnitude of the higher frequency terms.
Taken together, we see the higher frequency
noise contributes less and less to the final sum. We end up with a nice smooth
but varying noise map to use for displacement or whatever we want.
Normalizing
Summing several octaves means you will
typically get values greater than 1 (and less than -1 if you are using signed
noise).
There’s a few ways you can normalize these,
take a look at the commented out code. You might not want to map the minimum to
zero as it can cause jumps when the lower bound of the summed noise changes.
The app
An app to play with is up here
The small images show the individual
octaves, and the big image is the final result.
Also I used the noise function from that
app to do vertex displacement of a mesh and put a clip up here:
That’s it for now. Later on I will give an example of making seamless noise loops. I have a bunch of other stuff going on which I will write about when they are finished off, but I am really looking forward to sharing.
As always you can find me being rude and unprofessional on twitter. I love hearing from people, so tweet me pics of your rad noise stuff.
As always you can find me being rude and unprofessional on twitter. I love hearing from people, so tweet me pics of your rad noise stuff.
I think the code sample in the article is wrong. I looked at your code and the article by Paul Bourke. The input coordinate is run through a multiplicative sum. Same as with the alpha component. It should be noise(beta^n*x,beta^n*y) not noise(beta*n*x,beta*n*y), no?
ReplyDeleteYes I think you're right, good catch. I'll take a look closer at the weekend.
Delete