Perlin Noise module - need help to convert to Lua

Hi ,

I would like to make module to generate Perlin Noise but i have some problems with Lua conversion.

This is my class written in Monkey for Perlin Noise which works quite well. I think code is very well documented and is self explanatory but … its not Lua. You can use this code as You like.
This would the the output as example.
http://i53.tinypic.com/2ykzuao.png
http://i53.tinypic.com/2irvi89.png

EDIT: just removed non Lua Code

And this would be Lua version (still buggy)

[blockcode]

– CLASS
– BASIC PERLIN CLASS WITHOUT BITMAP

local sizeX = 640
local sizeY = 480

–first random noise table
local noiseArr = {}

–output table
local terrainArr = {}

–frequency, the lower the larger terrains of same level
local frequency = 1.0

–starting amplitude
local amplitude = 1.0

–change of amplitude of next octave
local persistance = 0.6

–number of octaves
local octaves = 8

–min and max colors
local colMin = {R = 0, G = 0, B = 0}
local colMax = {R = 200, G = 200, B = 200}

– some levels data
local levels = {}
local levelsColorR = {}
local levelsColorG = {}
local levelsColorB = {}

-----------------------------------------==
– just make some data, using fake 2D arrays
--------------------------------------------=
local function new(xx, yy)
sizeX = xx
sizeY = yy
noiseArr = {}
terrainArr = {}
end


– to init perlin noise parameters

local function changeParams(fre, amp, pers, oct)
frequency = fre
amplitude = amp
persistance = pers
octaves = oct
end

--------------------------------------------==
– perlin noise with linear interpolation
--------------------------------------------=
local function LinearFilterNoise(x, y)

local fractionX = x - math.floor(x)
local fractionY = y - math.floor(y)

local x1 = (math.floor(x) + sizeX) % sizeX
local y1 = (math.floor(y) + sizeY) % sizeY
local x2 = (math.floor(x) + sizeX - 1) % sizeX
local y2 = (math.floor(y) + sizeY - 1) % sizeY

if(x1 < 0) then
x1 = x1 + sizeX
end
if(x2 < 0) then
x2 = x2 + sizeX
end
if(y1 < 0) then
y1 = y1 + sizeY
end
if(y2 < 0) then
y2 = y2 + sizeY
end

local finVal = 0

finVal = finVal + fractionX * fractionY * noiseArr[x1 + y1*sizeX]
finVal = finVal + fractionX * (1 - fractionY) * noiseArr[x1 + y2*sizeX]
finVal = finVal + (1 - fractionX) * fractionY * noiseArr[x2 + y1 * sizeX]
finVal = finVal + (1 - fractionX) * (1 - fractionY) * noiseArr[x2 + y2*sizeX]

return finVal
end


– single field noise generation
-----------------------------------------==
local function getRandomNoise(x, y)
local fre = frequency
local amp = amplitude
local finalValue = 0.0

local i
for i = 1, octaves, 1 do
finalValue = finalValue + LinearFilterNoise(x * fre, y * fre) * amp
fre = fre * 2.0
amp = amp * persistance
end

if(finalValue < - 1.0) then
finalValue = -1.0
end
if(finalValue > 1.0) then
finalValue = 1.0
end

finalValue = finalValue * 0.5 + 0.5

return finalValue
end


– create output terrain array

local function MakeTerrainMap()
local x,y
for x = 1, sizeX, 1 do
for y = 1, sizeY, 1 do
terrainArr[x + y * sizeX] = getRandomNoise(x, y)
end
end
end

--------------------------------------------=
– to fill noise array with white noise
--------------------------------------------=
local function InitNoise()
noiseArr = {}
local x,y
for x = 1, sizeX, 1 do
for y = 1, sizeY, 1 do
noiseArr[x + y * sizeX] = (math.random() - 0.5) * 2.0
end
end
end

--------------------------------------------=
– might be usefull, process whole array with sinus
--------------------------------------------==
local function terrainSinus§
local x,y
for x = 1, sizeX, 1 do
for y = 1, sizeY, 1 do
local md = math.sin(y * 180 / sizeY) * 2 - 1
terrainArr[x + sizeX * y] = md * p + terrainArr[x + sizeX * y] * (1.0 - p)
end
end
end

-----------------------------------------==

-----------------------------------------==
– just make new data for colour perlin noise
--------------------------------------------=
local function NewColour(xx, yy)

new(xx,yy)

–init levels
local x
for x = 1, 100, 1 do
levels[x] = 0
end

end


– draw image

local function OnRender(scale, dx, dy)

local x,y
for x = 1, sizeX, 1 do
for y = 1, sizeY, 1 do

local val = terrainArr[x + sizeX * y]
local R = colMax.R * val + colMin.R * (1 - val)
local G = colMax.G * val + colMin.G * (1 - val)
local B = colMax.B * val + colMin.B * (1 - val)

–SetColor(R, G, B)
–DrawRect(x * scale + dx, y * scale + dy, scale, scale)

end
end
end


– draw image according to levels, like izolines

local function OnRenderLevel(scale, dx, dy)

local x,y
for x = 1, sizeX, 1 do
for y = 1, sizeY, 1 do

–terrain heigh
local val = terrainArr[x + sizeX * y]*99

–color ID
local val2 = levels[val]

–color itself
local valR = levelsColorR[val2]
local valG = levelsColorG[val2]
local valB = levelsColorB[val2]

–SetColor(val.R, val.G, val.B)
–DrawRect(x * scale + dx, y * scale + dy, scale, scale)

end
end
end
--------------------------------------------==
– start process
--------------------------------------------=
local function OnCreate()

InitNoise()
MakeTerrainMap()

end

--------------------------------------------==
– setup terrain N from lvl min to lvl max
– this is quantization of terrain to one color in range
– this creates area of same value = izo lines
--------------------------------------------=
local function setupLevel(levelMin, levelMax, val, nR,nG,nB)

levelsColorR[val] = nR
levelsColorG[val] = nG
levelsColorB[val] = nB

local x
for x = levelMin, levelMax, 1 do
levels[x] = val
end
end

–EXAMPLE OF USAGE

NewColour(64,48) --to fill screen
changeParams(0.1, 0.99, 0.65, 6) --experiment !!
colMin = {R = 0, G = 50, B = 50} --dark green
colMax = {R = 150, G = 200, B = 150} --light green

setupLevel(1,40,1,0,40,80) --low level water
setupLevel(40,80,2,40,240,40) --medium grass
setupLevel(80,100,3,140,140,0) --high rocks

OnCreate()

[/blockcode]

Bladum [import]uid: 99683 topic_id: 17281 reply_id: 317281[/import]

I used this version of a one dimesional Perlin noise.
Hope it helps
Here is the code:

[lua]-- perlin.lua

module(…, package.seeall)

function interpolate(a,b,x)
return (a*(1.0-x)) + (b*x)
end

function cos_interpolate(a,b,x)
local ft = x * math.pi
f = (1.0 - math.cos(ft))*0.5
return (a*(1.0-f)) + (b*f)
end

function newPerlin()

local perlin = {}

for idx = 1,512 do
perlin[#perlin+1] = math.random()
end

perlin.octate = 4
perlin.persistence = 0.25

function perlin:setOctaves(x)
perlin.octate = x
end

function perlin:setPersistence(x)
perlin.persistence = x
end

function perlin:noise_int(x)
local y = (x % 512)+1
return perlin[y]
end

function perlin:smooth_noise1(x)
return (self:noise_int(x)/2) + (self:noise_int(x-1)/4) + (self:noise_int(x+1)/4)
end

function perlin:interpolate_noise_1(x)
local ix,f = math.modf(x)
local v1 = self:smooth_noise1(ix)
local v2 = self:smooth_noise1(ix+1)
return cos_interpolate(v1,v2,f)
end

function perlin:noise(x)
local total = 0
local p = perlin.persistence
local n = perlin.octate-1
local freq, amplitud
for idx = 0,n do
freq = 2^idx
amplitud = p^idx
total = total + perlin:interpolate_noise_1(x*freq) * amplitud
end
total = math.min(total,1.0)
total = math.max(0.0,total)
return total
end
return perlin
end[/lua] [import]uid: 9975 topic_id: 17281 reply_id: 65330[/import]

And how do you use it? Looks really interesting if we can get 60fps with perlin noice… [import]uid: 12704 topic_id: 17281 reply_id: 67727[/import]

@eaguirre
That 1D perlin is great, thanks for sharing! [import]uid: 110373 topic_id: 17281 reply_id: 88208[/import]

I would like to see an example of this in use. I am unclear on how you are using it, since the use of perlin noise I am familiar with is in relation to shaders and procedural texturing.
[import]uid: 5317 topic_id: 17281 reply_id: 90082[/import]

Mike,
I come from a Renderman, metaSL, Maya, & Houdini background, so I’m right there with you.

Here is a little cheatsheet from my current app

[lua]-- setup
local perlin = require(“perlin”)
local noise = perlin.newPerlin()
local Time = system.getTimer
–then inside an enterFrame Listener

–(Time()/Period) * Amp
– this noise function below will give you a smooth 1d noise
local noiseNow = noise:interpolate_noise_1( Time()/100 ) -.5 [/lua] [import]uid: 110373 topic_id: 17281 reply_id: 90101[/import]

@noBlad

awesome, works great :slight_smile: [import]uid: 89663 topic_id: 17281 reply_id: 114125[/import]

Though I’d clean this one up since I found it very useful but had stagnant code that was not used. Also moved one function inside  newPerlin() to make it cleaner. 

module(..., package.seeall) function newPerlin() local perlin = {} for idx = 1,512 do perlin[#perlin+1] = math.random() end perlin.octate = 4 perlin.persistence = 0.25 function perlin:cos\_interpolate(a,b,x) local ft = x \* math.pi f = (1.0 - math.cos(ft))\*0.5 return (a\*(1.0-f)) + (b\*f) end function perlin:setOctaves(x) perlin.octate = x end function perlin:setPersistence(x) perlin.persistence = x end function perlin:noise\_int(x) local y = (x % 512)+1 return perlin[y] end function perlin:smooth\_noise1(x) return (self:noise\_int(x)/2) + (self:noise\_int(x-1)/4) + (self:noise\_int(x+1)/4) end function perlin:interpolate\_noise\_1(x) local ix,f = math.modf(x) local v1 = self:smooth\_noise1(ix) local v2 = self:smooth\_noise1(ix+1) return perlin:cos\_interpolate(v1,v2,f) end function perlin:noise(x) local total = 0 local p = perlin.persistence local n = perlin.octate-1 local freq, amplitude for idx = 0,n do freq = 2^idx amplitude = p^idx total = total + perlin:interpolate\_noise\_1(x\*freq) \* amplitude end total = math.min(total,1.0) total = math.max(0.0,total) return total end return perlin end

Though I’d clean this one up since I found it very useful but had stagnant code that was not used. Also moved one function inside  newPerlin() to make it cleaner. 

module(..., package.seeall) function newPerlin() local perlin = {} for idx = 1,512 do perlin[#perlin+1] = math.random() end perlin.octate = 4 perlin.persistence = 0.25 function perlin:cos\_interpolate(a,b,x) local ft = x \* math.pi f = (1.0 - math.cos(ft))\*0.5 return (a\*(1.0-f)) + (b\*f) end function perlin:setOctaves(x) perlin.octate = x end function perlin:setPersistence(x) perlin.persistence = x end function perlin:noise\_int(x) local y = (x % 512)+1 return perlin[y] end function perlin:smooth\_noise1(x) return (self:noise\_int(x)/2) + (self:noise\_int(x-1)/4) + (self:noise\_int(x+1)/4) end function perlin:interpolate\_noise\_1(x) local ix,f = math.modf(x) local v1 = self:smooth\_noise1(ix) local v2 = self:smooth\_noise1(ix+1) return perlin:cos\_interpolate(v1,v2,f) end function perlin:noise(x) local total = 0 local p = perlin.persistence local n = perlin.octate-1 local freq, amplitude for idx = 0,n do freq = 2^idx amplitude = p^idx total = total + perlin:interpolate\_noise\_1(x\*freq) \* amplitude end total = math.min(total,1.0) total = math.max(0.0,total) return total end return perlin end