# My perlin noise height map doesn't have smooth transitions and goes directly from black to white

I am using lua with the love2d engine to make infinite 2d tiled terrain with perlin noise. This is just the first step and I want to fix the bugs early. The problem is that there is no gradient between the black and white islands. There should be a smooth transition all through the map.

Also there is a line between the two chunks that I can't get rid of. I am completely lost and cannot figure these problems out. Here is what I am going for:

Here is my code.

seed = 257
local canvas = love.graphics.newCanvas()

function Interpolate(a, b, x)
ft = x * 3.1415927
f = (1 - math.cos(ft)) * 0.5

return  a*(1-f) + b*f
end

function Noise(x, y)
n = x + y * seed
n = bit.bxor((bit.lshift(n,13)),n)
return ( 1.0 - ( bit.band((n * (n * n * 15731 + 789221) +
1376312589), 0x7fffffff) / 1073741824.0))
end

function SmoothedNoise1(x, y)
corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1,
y+1)+Noise(x+1, y+1) ) / 16
sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x,
y+1) ) /  8
center  =  Noise(x, y) / 4
return corners + sides + center
end

function InterpolatedNoise_1(x, y)
integer_X, fractional_X = math.modf(x)
integer_Y, fractional_Y = math.modf(y)

v1 = SmoothedNoise1(integer_X,     integer_Y)
v2 = SmoothedNoise1(integer_X + 1, integer_Y)
v3 = SmoothedNoise1(integer_X,     integer_Y + 1)
v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1)

i1 = Interpolate(v1 , v2 , fractional_X)
i2 = Interpolate(v3 , v4 , fractional_X)

return Interpolate(i1 , i2 , fractional_Y)
end

function getExampleMap()
mapWidth = 400
mapHeight = 400
mapMin = InterpolatedNoise_1(0, 0)
mapMax = mapMin
map = {}
amp = 128
freq =32
octaves = 6
for x = 0, mapWidth - 1 do
map[x] = {}
for y = 0, mapHeight - 1 do
map[x][y] = 0
for i = 1, octaves do
map[x][y] = map[x][y] + getNoiseValue(x, y, freq / i,
amp / i)
end
mapMin = math.min(mapMin, map[x][y])
mapMax = math.max(mapMax, map[x][y])
end
end
-- /*scale the values between 0 and 255 for rendering in grey
scale.*/
mapMultiplier = 255 / (mapMax - mapMin)
for x = 0, mapWidth - 1 do
for y = 0, mapHeight - 1 do
map[x][y] = map[x][y] * mapMultiplier
end
end
end

function getExampleMap2()
mapWidth = 400
mapHeight = 400
mapMin = InterpolatedNoise_1(0, 0)
mapMax = mapMin
map2 = {}
amp = 128
freq =32
octaves = 6
for x = 400, (mapWidth + 400) do
map2[x] = {}
for y = 0, mapHeight - 1 do
map2[x][y] = 0
for i = 1, octaves do
map2[x][y] = map2[x][y] + getNoiseValue(x, y, freq / i,
amp / i)

end
mapMin = math.min(mapMin, map2[x][y])
mapMax = math.max(mapMax, map2[x][y])
end
end
-- /*scale the values between 0 and 255 for rendering in grey
scale.*/
mapMultiplier = 255 / (mapMax - mapMin)
for x = 400, (mapWidth + 400) do
for y = 0, mapHeight - 1 do
map2[x][y] = map2[x][y] * mapMultiplier
end
end
end

function getNoiseValue(x, y, freq, amp)
return InterpolatedNoise_1(x / freq, y / freq) * amp
end

love.window.setMode( 1920, 1080, {fullscreen=false})
getExampleMap()
getExampleMap2()
end

function love.draw()

for x = 0, mapWidth - 1 do
for y = 0, mapHeight - 1 do
love.graphics.setColor(map[x][y], map[x][y], map[x][y], 255)
love.graphics.point(x,y)
end
end
for x = 400, (mapWidth + 400) do
for y = 0, mapHeight - 1 do
love.graphics.setColor(map2[x][y], map2[x][y], map2[x][y],
255)
love.graphics.point(x,y)
end
end

end

function love.update()

end

function love.keyreleased(key)
if key == "escape" then
love.event.quit()
end
end

• I quite like the result you get - however if you don't get the result you want, it's because you aren't using the right algorithm. What you are doing is creating value noise, not Perlin noise. They get easily confused because of some articles on the Internet that call Perlin noise what really is value noise. I have a fairly good implementation of true Perlin noise written in Lua for the same purpose as yours. I will post it as an answer as soon as possible. – user6245072 Jul 28 '16 at 7:47
• The image you supplied looks like it would make for a nice ocean and mountain map. Just change the values until you get it right. – Krythic Nov 8 '16 at 15:15

There is a bug in the final normalisation code, fortunately it’s easy to fix. You only need to change:

map2[x][y] = map2[x][y] * mapMultiplier


into:

map2[x][y] = (map2[x][y] - mapMin) * mapMultiplier


As I said in the comments, what you are using is just value noise, not true Perlin noise. Here's my Lua implementation of true Perlin noise:

local function f(t)
return t * t * t * (t * (6 * t - 15) + 10)
end

local function l(t, a, b)
return a + t * (b - a)
end

local function g(h, x, y, z)
local h, u, v, r = h % 16
if h < 8 then u = x else u = y end
if h < 4 then v = y elseif h == (12 or 14) then v = x else v = z end
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
end

local m = math.modf
local function noise(o, x, y, z)
y, z = y or 1 / 3, z or 2 / 3
local f, l, g, m = f, l, g, m
local X, x = m(x % 256)
local Y, y = m(y % 256)
local Z, z = m(z % 256)
local u, v, w = f(x), f(y), f(z)
local A = o[X] + Y
local AA = o[A] + Z
local AB = o[A + 1] + Z
local B = o[X + 1] + Y
local BA = o[B] + Z
local BB = o[B + 1] + Z
return l(w, l(v, l(u, g(o[AA], x, y, z),
g(o[BA], x - 1, y, z)),
l(u, g(o[AB], x, y - 1, z),
g(o[BB], x - 1, y - 1, z))),
l(v, l(u, g(o[AA + 1], x, y, z - 1),
g(o[BA + 1], x - 1, y, z - 1)),
l(u, g(o[AB + 1], x, y - 1, z - 1),
g(o[BB + 1], x - 1, y - 1, z - 1))))
end

local m = {
__index = function(t, i)
return type(i) == "number" and t[i % 256] or noise
end}

return function(s)
local o = {}
local rand = math.random
local _ = s and math.randomseed(tonumber(s) or os.time())
for n = 0, 255 do
local t = rand(0, 255)
while o[t] do
t = rand(0, 255)
end
o[t] = n
end
return setmetatable(o, m)
end


Paste this code in a separated file in the same directory, then in your main.lua file do:

function love.load()
--Assuming you called the module perlin.lua
newperlin = require("perlin")
--newperlin is a function that generates Perlin noise objects:

myperlin = newperlin()
--when provided no arguments, newperlin seeds the Perlin object with the current time to create an always different result, but you can provide a seed which will create always the same result:
myperlin = newperlin(seed)

--then, to create noise:
local noise = myperlin:noise(x, y, z)
--y and z are optional; x is mandatory
end


Then see this question to understand how to actually get the result you asked for.

• Thank you user6245072 , I have decided to stick with my original code. But I can't figure out why there is a line between my 2 chunks as seen in the picture above. – digitalsoldier0 Jul 29 '16 at 10:01
• I think it's an error in the map generation code, as it is at the very center of the map, right where map1 ends and map2 starts, but I can't spot it. – user6245072 Jul 29 '16 at 12:59