Code archives/Algorithms/Perlin Noise Type
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| This is a Perlin Noise implementation for 2D maps with linear interpolation and usage of 3 layers = altitude, temperature and humidity. - different outputs available (as a separate layers or a whole world map) - one function setup with easy to change parameters | |||||
'==========================================
' CLASS
' main perlin noise class
'==========================================
Type CPerlinNoise
Field sizeX = 640
Field sizeY = 480
'first random noise table
Field noiseArr:Float[,] = New Float[sizeX, sizeY]
'output table
Field terrainArr:Float[,] = New Float[sizeX, sizeY]
'output bitmap
Field bitmapOut:TPixmap = TPixmap.Create(sizeX, sizeY, PF_RGBA8888)
'frequency, the lower the larger terrains of same level
Field frequency:Float = 1.0
'starting amplitude
Field amplitude:Float = 1.0
'change of amplitude of next octave
Field persistance:Float = 0.6
'number of octaves
Field octaves = 8
'min and max colors
Field colMin:CColor = CColor.Create(0, 0, 0)
Field colMax:CColor = CColor.Create(0, 0, 0)
'==========================================
' to init perlin noise values
'==========================================
Method ChangeParams(fre:Float, amp:Float, pers:Float, oct)
frequency = fre
amplitude = amp
persistance = pers
octaves = oct
End Method
'==========================================
' single field noise generation
'=========================================
Method GetRandomNoise:Float(x:Float, y:Float)
Local fre:Float = frequency
Local amp:Float = amplitude
Local finalValue:Float = 0.0
For Local i = 0 To octaves
finalValue = finalValue + LinearFIlterNoise(x * fre, y * fre) * amp
fre = fre * 2.0
amp = amp * persistance
Next
If(finalValue < - 1.0) finalValue = -1.0
If(finalValue > 1.0) finalValue = 1.0
finalValue = finalValue * 0.5 + 0.5
Return finalValue
End Method
'==========================================
' create output terrain array
'==========================================
Method MakeTerrainMap()
For Local x = 0 To sizeX - 1
For Local y = 0 To sizeY - 1
terrainArr[x, y] = GetRandomNoise(x, y)
Next
Next
End Method
'==========================================
' process bitmap to file
'==========================================
Method MakeBitmap()
bitmapOut.ClearPixels($FFFFFFFF)
For Local x = 0 To sizeX - 1
For Local y = 0 To sizeY - 1
Local val:Float = terrainArr[x, 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)
bitmapOut.WritePixel(x, y, $FF000000 + (R * $10000 + G * $100 + B))
Next
Next
End Method
'============================================
' perlin noise with linear interpolation
'===========================================
Method LinearFilterNoise:Float(x:Float, y:Float)
Local fractionX:Float = X - Int(X)
Local fractionY:Float = Y - Int(Y)
Local x1 = (Int(x) + sizeX) Mod sizeX
Local y1 = (Int(y) + sizeY) Mod sizeY
Local x2 = (Int(x) + sizeX - 1) Mod sizeX
Local y2 = (Int(y) + sizeY - 1) Mod sizeY
If(x1 < 0) x1 = x1 + sizeX
If(x2 < 0) x2 = x2 + sizeX
If(y1 < 0) y1 = y1 + sizeY
If(y2 < 0) y2 = y2 + sizeY
Local finVal:Float = 0
finVal = finVal + fractionX * fractionY * noiseArr[x1, y1]
finVal = finVal + fractionX * (1 - fractionY) * noiseArr[x1, y2]
finVal = finVal + (1 - fractionX) * fractionY * noiseArr[x2, y1]
finVal = finVal + (1 - fractionX) * (1 - fractionY) * noiseArr[x2, y2]
Return finVal
End Method
'===========================================
' to fill noise array with white noise
'===========================================
Method InitNoise()
noiseArr = New Float[sizeX, sizeY]
For Local x = 0 To sizeX - 1
For Local y = 0 To sizeY - 1
noiseArr[x, y] = (RndFloat() - 0.5) * 2.0
Next
Next
End Method
'===========================================
Method terrainSinus(p:Float)
For Local x = 0 To sizeX - 1
For Local y = 0 To sizeY - 1
Local md:Float = Sin(y * 180 / sizeY) * 2 - 1
terrainArr[x, y] = md * p + terrainArr[x, y] * (1.0 - p)
Next
Next
End Method
'============================================
' start process
'===========================================
Function Calculate()
'create altitude map
Local highMap:CPerlinNoise = New CPerlinNoise
highMap.ChangeParams(0.02, 0.95, 0.6, 6)
highMap.colMin = CColor.Create(0, 120, 0)
highMap.colMax = CColor.Create(100, 220, 100)
highMap.InitNoise()
highMap.MakeTerrainMap()
highMap.MakeBitmap()
SavePixmapPNG(highMap.bitmapOut, "high1.png")
'creat humitidy map
Local humMap:CPerlinNoise = New CPerlinNoise
humMap.ChangeParams(0.04, 0.99, 0.6, 6)
humMap.colMin = CColor.Create(0, 0, 20)
humMap.colMax = CColor.Create(0, 50, 120)
humMap.InitNoise()
humMap.MakeTerrainMap()
humMap.MakeBitmap()
SavePixmapPNG(humMap.bitmapOut, "high2.png")
'create temperature map
Local tempMap:CPerlinNoise = New CPerlinNoise
tempMap.ChangeParams(0.04, 0.99, 0.6, 6)
tempMap.colMin = CColor.Create(60, 0, 0)
tempMap.colMax = CColor.Create(240, 0, 0)
tempMap.InitNoise()
tempMap.MakeTerrainMap()
tempMap.terrainSinus(0.6)
tempMap.MakeBitmap()
SavePixmapPNG(tempMap.bitmapOut, "high3.png")
'generate additional world map
GenerateWorldMap(highMap, humMap, tempMap)
End Function
'=============================================
' generate simple world map
'=============================================
Function GenerateWorldMap(highMap:CPerlinNoise,humMap:CPerlinNoise,tempMap:CPerlinNoise)
Local pixies:TPixmap = TPixmap.Create(tempMap.sizeX, tempMap.sizeY, PF_RGBA8888)
For Local x = 0 To tempMap.sizeX - 1
For Local y = 0 To tempMap.sizeY - 1
Local T:Float = tempMap.terrainArr[x, y] * 2 - 1.0
Local H:Float = humMap.terrainArr[x, y] * 2 - 1.0
Local A:Float = highMap.terrainArr[x, y] * 2 - 1.0
Local R, G, B
'water
If(A < 0)
R = 0
G = 60 + A * 60
B = 120 + A * 100
'land
Else
'altitude
R = 60 + A * 180
G = 60 + A * 180
B = 60 + A * 180
'temperature
If(T >= 0)
G = G * (1.0 - T * 0.3)
B = B * (1.0 - T * 0.3)
Else
R = R * (1.0 + T * 0.3)
End If
'high humidity
If(H >= 0)
R = R * (1.0 - H * 0.3)
B = B * (1.0 - H * 0.3)
Else
G = G * (1.0 + H * 0.3)
End If
End If
'some final quantizations
R = (R / 15) * 15
G = (G / 15) * 15
B = (B / 15) * 15
pixies.WritePixel(x, y, $FF000000 + (R * $10000 + G * $100 + B))
Next
Next
SavePixmapPNG(pixies, "worldMap.png")
End Function
End Type
'==================================
' CLASS
'just simple class to help colors
'==================================
Type CColor
Field R = 0
Field G = 0
Field B = 0
'==================================
Function Create:CColor(r, g, b)
Local aa:CColor = New CColor
aa.R = r
aa.g = g
aa.b = b
Return aa
End Function
'==================================
Function Process:CColor(f:Long)
Local aa:CColor = New CColor
aa.R = f & $00FF0000
aa.R = aa.R / $10000
aa.G = f & $0000FF00
aa.G = aa.G / $100
aa.B = f & $000000FF
Return aa
End Function
End Type
'===========================================================
'===========================================================
'===========================================================
'===========================================================
'===========================================================
'===========================================================
'some simple setup
SetGraphicsDriver(GLMax2DDriver ())
Graphics(640, 480, 0, 60)
'run perlin noise
CPerlinNoise.Calculate()
Global img:TImage = LoadImage("worldMap.png")
While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
Cls()
DrawImage(img,0,0)
Flip(1)
Wend |
Comments
None.
Code Archives Forum