Basic Perlin Noise questions

Started by
6 comments, last by schupf 14 years, 1 month ago
Hello, In order to get a nice terrain (and clouds) I tried to delve into the field of Perlin Noise. Most of my knowledge I got from this article: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm This article has code for a 1 dimensional perlin noise function:
 function Noise1(integer x)
    x = (x<<13) ^ x;
    return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);    
  end function


  function SmoothedNoise_1(float x)
    return Noise(x)/2  +  Noise(x-1)/4  +  Noise(x+1)/4
  end function


  function InterpolatedNoise_1(float x)
      integer_X    = int(x)
      fractional_X = x - integer_X

      v1 = SmoothedNoise1(integer_X)
      v2 = SmoothedNoise1(integer_X + 1)

      return Interpolate(v1 , v2 , fractional_X)
  end function


  function PerlinNoise_1D(float x)
      total = 0
      p = persistence
      n = Number_Of_Octaves - 1

      loop i from 0 to n
          frequency = 2^i
          amplitude = p^i

          total = total + InterpolatedNoisei(x * frequency) * amplitude
      end of i loop

      return total
  end function
To check if I understood everything I'm gonna recap the code in my own words and you please tell me if I am right (or wrong): You have a function Noise1 which returns a pseudo random number in interval [-1,1] for an integer. For example it returns 0.3 for 2, -0.8 for 3 and so on. To get values BETWEEN these integer values you have the function InterpolatedNoise_1. These function returns values in [-1,1] for all fractional values. The main function PerlinNoise_1D does this: It adds n octaves, where each octave has twice the frequency than the previous octave and the amplitude gets smaller. For every octave you use an another InterpolatedNoise function. Becuase if you used the same InterpolateNoise function for every octave you would sample the same "graph" again and again (just with other frequency). Is this correct? My other questions: 2) In the whole document nothing is mentioned about gradients or vectors. In some other papers I have read that Perlin Noise uses gradients in a integer grid. Now I am confused what Perlin Noise is really about. Does the cited article from hugo elias really describe pure Perlin Noise? Is Perlin Noise just "adding up functions with increasing frequency and decreasing amplitude"? 3) I am not sure how I could use Perlin Noise to generate a heightmap. I mean the Perlin Noise function returns me a value for EVERY float. I get a value for 2, for 2.33, for 10433.2 and so on. How is this related to my heightmap resolution?
Advertisement
Hugo Elias' page does not actually describe perlin noise.

What he calls InterpolatedNoise_1 is generally termed 'value noise', and what he calls PerlinNoise_1D is actually 'fractal brownian motion'.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

I'm certainly no expert here, but it sounds right so far. It doesn't sound like you've read the entire page though, as he goes on to define the necessary function Noise(x, y) as well as the cubic interpolation function for it, which is what you will use for heightmap creation.
Quote:3) I am not sure how I could use Perlin Noise to generate a heightmap. I mean the Perlin Noise function returns me a value for EVERY float. I get a value for 2, for 2.33, for 10433.2 and so on. How is this related to my heightmap resolution?


for (int z = 0; z < length_of_heightmap; z += step){for (int x = 0; x < width_of_heightmap; x += step){int y = getValueFromPerlinNoise(x, z);vector3(x, y, z); // actual heightmap position}}


you meant something like this?
what you get is basically a grid with different heights that correspond to the perlin noise
Since its the first time for me to deal with this topic I have to believe what I read.
Can anyone confirm swiftcoder statement that hugo elias' doesnt describe perlin noise (though his article is called perlin noise)?

@BLiTZWiNG: I've read the whole article and of course I've seen his code for the 2D case. Though I am still not 100% sure how to use this 2D code for my heightmap generation.
Take a look at projectghost's code. He iterates over the grid and executes the perlin noise at every integer position (x and z are integer values). But when I sample the noise function only at integer positions there would never be some form of interpolation, wouldnt it?
Quote:Original post by schupf
Can anyone confirm swiftcoder statement that hugo elias' doesnt describe perlin noise (though his article is called perlin noise)?
That page is single-handedly responsible for the widespread misunderstanding of perlin noise.

Perlin noise (as you mentioned at the outset) is gradient noise, where as Hugo Elias' noise is value noise. The difference is fairly subtle until you take the first derivative (i.e. derive a normal map), when you will see that Perlin/Simplex noise is continuous in its first derivative, while value noise is not.

See Perlin's own presentation for a quick overview of perlin noise.
Quote:Take a look at projectghost's code. He iterates over the grid and executes the perlin noise at every integer position (x and z are integer values). But when I sample the noise function only at integer positions there would never be some form of interpolation, wouldnt it?
Generally one would scale those integer coordinates, so as to sample the noise function omn the range [0,1]. You are correct that sampling on an integer grid will look like pure noise, rather than interpolated noise.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

If you use Perlin's gradient noise, sampling on the grid will result in values of 0 across the board, as gradient noise is always 0 at integer boundaries. It might benefit you to write a general-case function to map any given range of noise into your buffer:

Buffer: 2D array of samples, heightfieldWidth/Height: dimensions of BufferNoise(x,y) : Noise functionx1,y1,x2,y2 : Desired mapping rangefor i=0 to Width-1 do  for j=0 to Height-1 do    s = i/(Width-1)    t = j/(Height-1)    nx=x1 + s*(x2-x1)    ny=y1 + t*(y2-y1)    Buffer[j]=Noise(nx,ny)  endend


With a generalized function, you can change the domain by changing (x1,y1) and (x2,y2), and thus change the size of the area of noise that is sampled as the heightfield.

For a good description of both gradient and simplex noise, see this paper.
Quote:Original post by swiftcoderThat page is single-handedly responsible for the widespread misunderstanding of perlin noise.

Oh, I see. It was the first article I've read about Perlin Noise and as a beginner you have to believe what you read. Thanks for clarifying that Hugos article is very misleading.

@JTippetts: I think I've understood your code. The variables x1,y1,x2,y2 define the range in which the value noise function is sampled. The first octaves define the "macro" structure of the terrain. If I want a terrain with only a few big mountains I choose a small range and if I want a terrain with a lot of big mountains I choose a big range. Please tell me if I am wrong.

This topic is closed to new replies.

Advertisement