Sign up ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm using 2d perlin noise to generate a heightmap and then adding 3d perlin noise to the heightmap to create overhangs and ridges. But it's not turning out like I would like it to. There are too many hills that don't look good and lots of different places where it's flat. This is the perlin noise function I'm using for both the 2d and 3d (in LUA):

function noise(x, y, z) 
  local X = math.floor(x % 255)
  local Y = math.floor(y % 255)
  local Z = math.floor(z % 255)
  x = x - math.floor(x)
  y = y - math.floor(y)
  z = z - math.floor(z)
  local u = fade(x)
  local v = fade(y)
  local w = fade(z)

  A   = p[X  ]+Y
  AA  = p[A]+Z
  AB  = p[A+1]+Z
  B   = p[X+1]+Y
  BA  = p[B]+Z
  BB  = p[B+1]+Z

  return lerp(w, lerp(v, lerp(u, grad(p[AA  ], x  , y  , z   ), 
                                 grad(p[BA  ], x-1, y  , z   )), 
                         lerp(u, grad(p[AB  ], x  , y-1, z   ), 
                                 grad(p[BB  ], x-1, y-1, z   ))),
                 lerp(v, lerp(u, grad(p[AA+1], x  , y  , z-1 ),  
                                 grad(p[BA+1], x-1, y  , z-1 )),
                         lerp(u, grad(p[AB+1], x  , y-1, z-1 ),
                                 grad(p[BB+1], x-1, y-1, z-1 )))

function fade(t)
  return t * t * t * (t * (t * 6 - 15) + 10)

function lerp(t,a,b)
  return a + t * (b - a)

function grad(hash,x,y,z)
  local h = hash % 16
  local u 
  local v 

  if (h<8) then u = x else u = y end
  if (h<4) then v = y elseif (h==12 or h==14) then v=x else v=z end
  local r

  if ((h%2) == 0) then r=u else r=-u end
  if ((h%4) == 0) then r=r+v else r=r-v end
  return r

p = {}
local permutation = {151,160,137,91,90,15,
  190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
  88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
  102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
  135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
  223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
  129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
  251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
  49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,

for i=0,255 do
  p[i] = permutation[i+1]
  p[256+i] = permutation[i+1]

You can also find the implementation, written by Perlin himself, here:

And this is how my loop looks like:

local smoothness = math.random(20, 30)
    for x = 1, mapScale do
        for z = 1, mapScale do
            local height = noise(x/smoothness, z/smoothness, 0) --Find out the height 
            for y = 1, (height*mapHeight)+10 do
                local density = noise(x/smoothness, y/smoothness, z/smoothness) --Find out the density
                if y > waterLvl then
                    if density*10 > 0 then
                        t:setCell(x, y, z, 1, 0, 0) --Sets cell at position x, y, z
                    t:setCell(x, y, z, 1, 0, 0)

This is how it turns out to be:

How would I change the frequency, number of octaves, and persistence with this function since it doesn't take any parameters for them?

share|improve this question
Greetings, user, and welcome to the GameDev stack. You say your code is not producing output you like. Can you show us the output you're getting, and indicate why/where it's not matching up with your expectations? – fnord Jul 5 '13 at 22:22
Perlin noise is just a guaranteed smooth, random distribution of data from 0..1. 3D perlin just makes it smooth in a cube. What do you expect to see? – Patrick Hughes Jul 5 '13 at 22:36
I added a picture so you can see how it looks like. – Spynaz Jul 5 '13 at 23:28
You could also check out libnoise, featured in a related answer. – congusbongus Jul 6 '13 at 0:24
At this point you need to read the documentation to the two noise libraries mentioned, and then if there's a term you don't understand it then head to google. For example, libnoise has a really nice glossary to get you started. – Patrick Hughes Jul 6 '13 at 19:32

2 Answers 2

You are ONLY generating Perlin noise. This is actually the same as using only one octave, at any frequency. You can base yourself to implent FBM (Fractional Bownian Moment), It is actually how all engines use to make Perlin noise more fractal looking.

Bringing it down to code, you can use it like this:

//pseudo code
function fBm(float x, float y, float z, int octaves = 8, float lacunarity = 2.0, float gain = 0.5)
    float amplitude = 1.0;
    float frequency = 1.0;
    float sum = 0.0;
    for(int i = 0; i < octaves; ++i)
        sum += amplitude * noise(x * frequency, y * frequency, z * frequency);
        amplitude *= gain;
        frequency *= lacunarity;
    return sum;

You can change this line

sum += amplitude * noise(x * frequency, y * frequency, z * frequency);

with some other noise functions to generate some cool effects, for example:

sum += amplitude * (1-abs(noise(x * frequency, y * frequency, z * frequency)));

and you'll have a cool eroded terrain, with lots of straight mountains. Having a nice terrain is a game of playing with parameters, don't expect a already made "recipe", try to make your own!

share|improve this answer
Thanks a lot! That seems to make my terrain look a bit better. – Spynaz Jul 7 '13 at 16:44
One tip is to try to render the generated heightmap on an texture, then saving it on disk. Should help a lot to understand how your noise is looking. – Gustavo Maciel Jul 7 '13 at 16:48
@Spynaz If the answer helped to solve your problem, please mark it as accepted. – Gustavo Maciel Jul 9 '13 at 6:59

I have an idea that, since you can use different octaves, you can make harmonics using multiple resolutions of perlin noise.

8, 4, 2, 1 as octaves would superposition itself nicely, I think.

The only problem with this is that it might not be 100% "random" in that you use the same seed for each octave.

The key here is the word "superposition"

share|improve this answer
Well, all these methods are called pseudo-random because of that, but that's the usual way to do it. All number generators in a computer are seed-dependent. If you want the simulation to become really hard of being replicated with the same seed, a simple solution is to set the seed to the current second, or millisecond, or frame number, since the game started. – MAnd Nov 26 at 20:43

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.