32
\$\begingroup\$

I'm toying with Perlin Noise after some work with Diamond Square. I followed the implementation by Hugo Elias that basically, makes a series of functions with x,y as input to throw each coordinate value.

My PHP code is here:

I have two questions:

How do I use the algorithm to generate a height map in an array? I did not fully understand it and just ported to PHP the pseudocode, but doing the last function (map_perlined) after reading somewhere that the algorithm "magically" gives you transitioned values for each x,y point given (apparently, without having to read its adjacent values), I just get this when using as random function mt_rand(-100,100)/100;

enter image description here

And this when using the cryptographic: 1.0-(($n*($n*$n*15731+789221)+1376312589)&0x7fffffff)/1073741824.0; (which, BTW, can be implemented "as-is" in PHP?):

enter image description here

So, summing up, three questions:

  1. Is my code correct?
  2. The random function can be ported to PHP as described in the code? It throws no errors, but the results are not there.
  3. How do I actually use the algorithm?

UPDATE

Ok, made a PHP port of the code shown in Gustavson paper, and as other coder said, it just generate one octave. Have any other useful site/paper/guide about how to use this with the concepts of multiple octaves, amplitude, frequency, etc. to control the noise function? On Gustavson's paper just shows the results, not the actual implementation of the algorithm, perhaps i'm missing something?

UPDATE 2
@NATHAN

I made something like:

$persistence = 0.5;

for ($j = 0; $j < $size; $j++) {
    for ($i = 0; $i < $size; $i++) {

        for ($o = 0; $o < 8; $o++) {
            $frequency = pow(2,$o);
            $amplitude = pow($persistence, $o);
            $value += SimplexNoise($i*$frequency, $j * $frequency) * $amplitude;
            }

            //$value = SimplexNoise($i, $j) + 0.5 * SimplexNoise($i, $j) + 0.25 * SimplexNoise($i, $j);
            $this->mapArray[$i][$j] = new Cell($value);

And after normalizing the values to 0..1, I get a rather dull height map such as:

enter image description here

How do I seed the map? Perhaps what I need to implement is the 3d version with the third value a random height? But if so, I'd have to find out to take in consideration neighbour values, which I'd be ending with something like a diamond square algorithm, exactly what I do not want to do.

UPDATE 3

More Perlin work. I have yet to find a way to guide the noise to my results. Check these octaves and the final result:

Octave I to IV

Octave1Octave2Octave3Octave4

Summed up

Octaves 1-4 summed

Each octave is pretty much the same. Check the code:

$persistence = 0.5;

    for ($j = 0; $j < $size; $j++) {
      for ($i = 0; $i < $size; $i++) {
        $value = 0;

        for ($o = 0; $o < 4; $o++) {
          $frequency = pow(2,$o);
          $amplitude = pow($persistence, $o);
          $value += improved_noise($i*$frequency, $j*$frequency, 0.5)*$amplitude;

        }
        $this->map[$i][$j] = new Cell($value);

The results are normalized. What would you use have a strong influence in the development of the noise? I see examples where changing the amplitude gives soft or rough surfaces, but even if I give a huge amplitude, I see little difference.

\$\endgroup\$
3
  • \$\begingroup\$ Just add together multiple instances, increasing the frequency and decreasing the amplitude each time, like: perlin(x) + 0.5 * perlin(2*x) + 0.25 * perlin(4*x) + ... (for as many octaves as you want). You can also try altering the factors to get different looks; they don't need to be powers of 2. \$\endgroup\$ Oct 12, 2011 at 6:44
  • 1
    \$\begingroup\$ Post-Update, it looks you are not scaling Y correctly - I am too tired to grok the PHP (as I don't know PHP); but I hit a similar issue in my home tongue when implementing perlin the first time. Also kill the octaves and just debug one level of perlin. \$\endgroup\$ Oct 12, 2011 at 22:29
  • \$\begingroup\$ Anyone for my III update? \$\endgroup\$
    – Gabriel
    Oct 24, 2011 at 16:47

2 Answers 2

29
\$\begingroup\$

What you implemented isn't Perlin noise. I'm not sure why Hugo Elias says it is, but he's confused. Here is Ken Perlin's reference implementation. It doesn't actually call any external random number generator, but uses a built-in hash function to produce the pseudorandom gradient vectors.

Note also that Perlin noise consists of just one octave. Summing up multiple octaves (scaled instances of the noise function), as Hugo Elias suggests, is a useful technique, but not part of Perlin noise. What you get by doing that is called fractal noise, sometimes "fractal Brownian noise" (because of the supposed similiarity to Brownian motion).

If you want to understand geometrically what the algorithm is doing, try this paper. It's about a different kind of noise called "simplex noise", but also includes an explanation of classic Perlin noise. Incidentally, simplex noise was also invented by Perlin and is supposed to be an improvement over his classic noise, so you might try implementing it too if you're interested in playing with noise functions.

\$\endgroup\$
8
  • 2
    \$\begingroup\$ +1 for the Gustavson's paper. It explains both the perlin and simplex noise in the clearest way I've seen so far. Obviously simplex noise rules! \$\endgroup\$
    – FxIII
    Oct 10, 2011 at 9:58
  • \$\begingroup\$ I also found that paper some time ago but Hugo's looked more simple. I'll read it and give it a shot! Thanks! \$\endgroup\$
    – Gabriel
    Oct 10, 2011 at 17:14
  • 2
    \$\begingroup\$ be careful when downloading simplex noise, it might have a virus ;) \$\endgroup\$
    – bobobobo
    Oct 12, 2011 at 18:31
  • \$\begingroup\$ I know this is an old topic, but saying that the reference implementation doesn't use a random number is incorrect. When the library is initialized (or the first time a noise function is called) 256 random gradients are generated. The hashing you refer to is merely to coerce the infinite set of integers into the [0, 255] range that's cached. Essentially this is just a look-up table optimization, and the algorithm works just as well if, for instance, you seed a PRNG with a grid coordinate and use that to generate the gradient, it's just (much) slower that way. \$\endgroup\$
    – bcrist
    May 2, 2014 at 2:17
  • \$\begingroup\$ @bcrist I think you're referring to an older version of Perlin noise. Perlin's "improved noise", which I linked to, uses a fixed set of 12 gradient vectors, not 256 random ones. It uses a permutation table as a hash function to map grid coordinates to one of those 12 gradient vectors. \$\endgroup\$ May 2, 2014 at 2:30
11
\$\begingroup\$

That's a common misconception. What Hugo Elias calls "Perlin" noise is in fact fractal, or pink, noise. To better understand what Perlin noise is, you can read Perlin's article linked in Nathan Reed's answer, or libnoise docs (there's the same error there: Perlin noise is what they call Gradient noise), or CoherentNoise docs.

Now, to actually answer your question: you didn't get the expected result because noise frequency is too high. Your frequencies start with 1 and increase, meaning that every pixel in the resulting map has a random value. To see finer structure of the map, you need to "zoom in" on the noise. I don't really speak PHP, but I suppose the code should look like this:

$arrayMap[$i][$j] = PerlinNoise_2D($i/$width, $j/$height, $p, $octaves);

That is, you "stretch" one period of noise over your entire map. Of course, you can use other coefficients - just try different ones, see what happens.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the coherent noise docs! I see that you've written it :) What's the error in libnoise docs? Isn't Perlin noise a kind of gradient noise? \$\endgroup\$
    – legends2k
    Jul 31, 2019 at 9:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .