Pages

Friday, April 25, 2014

Fractional sums of Perlin Noise


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. 

2 comments:

  1. 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?

    ReplyDelete
    Replies
    1. Yes I think you're right, good catch. I'll take a look closer at the weekend.

      Delete