Code archives/Algorithms/2D and 3D simplex noise

This code has been declared by its author to be Public Domain code.

Download source code

2D and 3D simplex noise by Kittomer2012
A very fast simplex noise generator.

I use this one in my Dragoncraft game for runtime landscape generation.

It's a blitzmax conversion of this code:
http://webstaff.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf

Since the original code is public domain, this one is, too!
SuperStrict

Const _NoiseSize:Int = 256

Graphics (_NoiseSize, _NoiseSize)

Global _Noise:SimplexNoise = New SimplexNoise

Global _Z:Float

Global _Scale:Float = 0.01

Global _Image:TImage = CreateImage(_NoiseSize, _NoiseSize, 1, DYNAMICIMAGE)

Global _Pixmap:TPixmap

Global _temp:Float

Global _fpsMS:Int
Global _MSperFrame:Int
Global _lasttime:Int = MilliSecs()
Global _FPSCount:Int
Global _FPS:Int

While Not AppTerminate()

	If KeyDown (KEY_ESCAPE)
	
		End
	
	End If

	If KeyDown (KEY_R)
	
		_Noise.Randomize()
	
	End If
	
	'Increase or decrease scale
	If KeyDown (KEY_LEFT)
	
		_Scale:+0.001
	
	End If
	
	If KeyDown (KEY_RIGHT)
	
		If _Scale > 0 _Scale:-0.001
	
	End If
	
	'Increase or decrease Z-coordinate (animates noise)
	
	If KeyDown (KEY_UP)
	
		_Z:+0.01
	
	End If
	
	If KeyDown (KEY_DOWN)
	
		If _Z > 0 _Z:-0.01
	
	End If
	
	'Create Noise	
	_Pixmap = LockImage(_Image)
	
	For Local _x:Int = 0 To _NoiseSize - 1
		
		For Local _y:Int = 0 To _NoiseSize - 1
		
			_temp = _Noise.Noise_3D(_x * _Scale, _y * _Scale, _Z)
			
			_temp = (_temp + 1.0) / 2 'Normalize output range from -1.0/+1.0 to 0.0/1.0
			
			_Pixmap.WritePixel(_x, _y, argb(_temp * 255, _temp * 255, _temp * 255, 255))
				
		Next
			
	Next
		
	UnlockImage (_Image)
	
	Cls
	
	If _Image <> Null DrawImage (_Image, 0, 0)
		
	SetColor (0, 255, 0)
	
	DrawText ("Noise Scale: " + _Scale, 10, 10)
	DrawText ("Z Coordinate: " + _Z, 10, 25)
	DrawText ("FPS: " + _FPS, 10, 40)
	
	SetColor (255, 255, 255)
	
	Flip
	
	FPS()

Wend

'Simplex noise in 2D and 3D
Type SimplexNoise
	
	'Gradient table
	Field grad3:grad[] = [New Grad.Create(1, 1, 0), New Grad.Create(-1, 1, 0), New Grad.Create(1, -1, 0), New Grad.Create(-1, -1, 0),  ..
						 New Grad.Create(1, 0, 1), New Grad.Create(-1, 0, 1), New Grad.Create(1, 0, -1), New Grad.Create(-1, 0, -1),  ..
						 New Grad.Create(0, 1, 1), New Grad.Create(0, -1, 1), New Grad.Create(0, 1, -1), New Grad.Create(0, -1, -1)]
	
	'Permutation table.
	Field perm:Int[] = New Int[512]
	
	'Permutation table containing precomputed, mod12'd perm table.
	Field permMod12:Int[] = New Int[512]
	
	'Precomputed skew factors.
	Field F2:Float = 0.5 * (Sqr(3.0) - 1.0)
	Field G2:Float = (3.0 - Sqr(3.0)) / 6.0
	Field F3:Float = 1.0 / 3.0
	Field G3:Float = 1.0 / 6.0
  	
	Method New()
	
		'Randomize the permutation tables.
		For Local I:Int = 0 To 511
			perm[I] = Rand (0, 255)
			permMod12[I] = perm[I] Mod 12
		Next
		
	End Method
	
	'Re-Randomize the permutation tables.
	Method Randomize()
	
		For Local I:Int = 0 To 511
			perm[I] = Rand (0, 255)
			permMod12[I] = perm[I] Mod 12
		Next
		
	End Method
	
	'Should be faster than Floor()
	Method FastFloor:Int(x:Float)
	
		Local y:Int
	
		If x > 0
			y = Int (x)
		Else
			y = Int (x - 1)
		End If
		
		Return y
		
	End Method
	
	'Dot product for 3D Noise
	Method Dot3D:Float (g:Grad, x:Float, y:Float, z:Float)
	
	Return g.x * x + g.y * y + g.z * z
	
	EndMethod
	
	'Dot product for 2D Noise
	Method Dot2D:Float (g:Grad, x:Float, y:Float)
	
	Return g.x * x + g.y * y
	
	EndMethod
	
  	' 2D simplex noise
  	Method Noise_2D:Float (xin:Float, yin:Float)
		
		' Noise contributions from the three corners
	    Local n0:Float, n1:Float, n2:Float
		
	    ' Skew the input space to determine which simplex cell we're in
		Local s:Float = (xin + yin) * F2 ' Hairy factor for 2D
		
	    Local I:Int = FastFloor(xin + s)
	    Local j:Int = FastFloor(yin + s)
		
	    Local t:Float = (I + j) * G2
		
		' Unskew the cell origin back to (x,y) space
	    Local X0:Float = I - t
	    Local Y0:Float = j - t
		
		' The x,y distances from the cell origin
	    X0 = xin - X0
	    Y0 = yin - Y0
		
	    'For the 2D case, the simplex shape is an equilateral triangle.
	    'Determine which simplex we are in.
		
		'Offsets for second (middle) corner of simplex in (i,j) coords
	    Local i1:Int, j1:Int
		
	    If X0 > Y0 Then
			' lower triangle, XY order: (0,0)->(1,0)->(1,1)
	    	i1 = 1
			j1 = 0
	    Else
			' upper triangle, YX order: (0,0)->(0,1)->(1,1)
			i1 = 0
			j1 = 1
		EndIf
		
	    ' A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
	    ' a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
	    ' c = (3-sqrt(3))/6
		
		' Offsets for middle corner in (x,y) unskewed coords
	    Local x1:Float = x0 - i1 + G2
	    Local y1:Float = y0 - j1 + G2
		
		' Offsets for last corner in (x,y) unskewed coords
	    Local x2:Float = x0 - 1.0 + 2.0 * G2
	    Local y2:Float = y0 - 1.0 + 2.0 * G2
		
	    ' Work out the hashed gradient indices of the three simplex corners
	    Local ii:Int = I & 255
	    Local jj:Int = j & 255
	    Local gi0:Int = permMod12[ii + perm[jj]]
	    Local gi1:Int = permMod12[ii + i1 + perm[jj + j1]]
	    Local gi2:Int = permMod12[ii + 1 + perm[jj + 1]]
		
	    ' Calculate the contribution from the three corners
	    Local t0:Float = 0.5 - X0 * X0 - Y0 * Y0
		
	    If t0 < 0 Then
			n0 = 0.0
	    Else
	    	t0 = t0 * t0
	    	n0 = t0 * t0 * Dot2D(grad3[gi0], X0, Y0) ' (x,y) of grad3 used for 2D gradient
	    EndIf
		
	    Local t1:Float = 0.5 - x1 * x1 - y1 * y1
		
	    If t1 < 0 Then
			n1 = 0.0
	    Else
			t1 = t1 * t1
	    	n1 = t1 * t1 * Dot2D(grad3[gi1], x1, y1)
	    EndIf
		
	    Local t2:Float = 0.5 - x2 * x2 - y2 * y2
		
	    If t2 < 0 Then
			n2 = 0.0
	    Else
	    	t2 = t2 * t2
	    	n2 = t2 * t2 * Dot2D(grad3[gi2], x2, y2)
	    EndIf
		
	    ' Add contributions from each corner to get the final noise value.
	    ' The result is scaled to return values in the interval [-1,1].
	    Return 70.0 * (n0 + n1 + n2)
		
  	EndMethod
	
	' 3D simplex noise
	Method Noise_3D:Float(xin:Float, yin:Float, zin:Float)
	    
		' Noise contributions from the four corners
		Local n0:Float, n1:Float, n2:Float, n3:Float
	    
		' Skew the input space to determine which simplex cell we're in
	    Local s:Float = (xin + yin + zin) * F3 ' Very nice And simple skew factor For 3D
	    Local I:Int = fastfloor(xin + s)
	    Local j:Int = fastfloor(yin + s)
	    Local k:Int = fastfloor(zin + s)
		
	    Local t:Float = (I + j + k) * G3
		
		' Unskew the cell origin back to (x,y,z) space
	    Local X0:Float = I - t
	    Local Y0:Float = j - t
	    Local Z0:Float = k - t
		
		' The x,y,z distances from the cell origin
	    X0 = xin - X0
	    Y0 = yin - Y0
	    Z0 = zin - Z0
		
	    ' For the 3D case, the simplex shape is a slightly irregular tetrahedron.
	    ' Determine which simplex we are in.
		
		' Offsets for second corner of simplex in (i,j,k) coords
	    Local i1:Int, j1:Int, k1:Int
		
		' Offsets for third corner of simplex in (i,j,k) coords
	    Local i2:Int, j2:Int, k2:Int
		
	    If X0 >= Y0 Then
	    	If Y0 >= Z0 Then
	        	i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0 ' X Y Z order
	        Else If X0 >= Z0
				i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1 ' X Z Y order
	        Else
				i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1 ' Z X Y order
	    	EndIf
	    Else ' x0<y0
	    	If Y0 < Z0
		  		i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1 ' Z Y X order
		  	Else If X0 < Z0
				i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1 ' Y Z X order
	      	Else
				i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0 ' Y X Z order
			EndIf
	    EndIf
		
	    ' A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
	    ' a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
	    ' a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
	    ' c = 1/6.
		
		' Offsets for second corner in (x,y,z) coords
	    Local x1:Float = X0 - i1 + G3
	    Local y1:Float = Y0 - j1 + G3
	    Local z1:Float = Z0 - k1 + G3
		
		' Offsets for third corner in (x,y,z) coords
	    Local x2:Float = X0 - i2 + 2.0 * G3
	    Local y2:Float = Y0 - j2 + 2.0 * G3
	    Local z2:Float = Z0 - k2 + 2.0 * G3
		
		' Offsets for last corner in (x,y,z) coords
	    Local x3:Float = X0 - 1.0 + 3.0 * G3
	    Local y3:Float = Y0 - 1.0 + 3.0 * G3
	    Local z3:Float = Z0 - 1.0 + 3.0 * G3
		
	    ' Work out the hashed gradient indices of the four simplex corners
	    Local ii:Int = I & 255
	    Local jj:Int = j & 255
	    Local kk:Int = k & 255
	    Local gi0:Int = permMod12[ii + perm[jj + perm[kk]] ]
	    Local gi1:Int = permMod12[ii + i1 + perm[jj + j1 + perm[kk + k1]] ]
	    Local gi2:Int = permMod12[ii + i2 + perm[jj + j2 + perm[kk + k2]] ]
	    Local gi3:Int = permMod12[ii + 1 + perm[jj + 1 + perm[kk + 1]] ]
		
	    ' Calculate the contribution from the four corners
		
	    Local t0:Float = 0.6 - x0 * x0 - y0 * y0 - z0 * z0
		
	    If t0 < 0
			n0 = 0.0
		Else
	      t0 = t0 * t0
	      n0 = t0 * t0 * Dot3D (grad3[gi0], X0, Y0, Z0)
	    EndIf
		
	    Local t1:Float = 0.6 - x1 * x1 - y1 * y1 - z1 * z1
		
	    If t1 < 0
			n1 = 0.0
	    Else
	      t1 = t1 * t1
	      n1 = t1 * t1 * Dot3D(grad3[gi1], x1, y1, z1)
	    EndIf
		
	    Local t2:Float = 0.6 - x2 * x2 - y2 * y2 - z2 * z2
		
	    If t2 < 0
			n2 = 0.0
	    Else
	      t2 = t2 * t2
	      n2 = t2 * t2 * Dot3D(grad3[gi2], x2, y2, z2)
	    EndIf
		
	    Local t3:Float = 0.6 - x3 * x3 - y3 * y3 - z3 * z3
		
	    If t3 < 0
			n3 = 0.0
	    Else
	      t3 = t3 * t3
	      n3 = t3 * t3 * Dot3D(grad3[gi3], x3, y3, z3)
	    EndIf
		
	    ' Add contributions from each corner to get the final noise value.
	    ' The result is scaled to stay just inside [-1,1]
	    Return 32.0 * (n0 + n1 + n2 + n3)
		
	EndMethod

EndType

'Custom data type for simplex noise gradient definition.
Type Grad

	Field x:Float, y:Float, z:Float
	
	Method Create:grad(x:Float, y:Float, z:Float = 0.0)
	
		Self.x = x
		Self.y = y
		Self.z = z
		
		Return Self
	
	End Method

EndType

Function argb:Int(_red:Int, _green:Int, _blue:Int, _alpha:Int)
	
	Local _argb:Int = 256 * 256 * 256 * _alpha + 256 * 256 * _blue + 256 * _green + _red
	
	Return _argb
		
End Function

Function FPS()
	
	_fpsMS:+MilliSecs() - _lasttime
	_MSperFrame = (MilliSecs() - _lasttime) '* 0.01
	_lasttime = MilliSecs()
	_FPSCount:+1
			
	If (_fpsMS >= 1000)
		_FPS = _FPSCount
		_FPSCount = 0
		_fpsMS:-1000
	End If

End Function

Comments

GW2012
Pretty cool!
You should add an offset x/y too.

oh,nevermind. (_x * _Scale)+offset


Code Archives Forum