Code archives/Algorithms/2D and 3D simplex noise
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
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
| ||
Pretty cool! You should add an offset x/y too. oh,nevermind. (_x * _Scale)+offset |
Code Archives Forum