License Public Domain
Lines 64
Keywords
noise (2) perlin (2)
Permissions
Owner: Stou S.
Viewable by Everyone
Editable by All Siafoo Users
Hide
Don't get spied on – We respect your privacy and provide numerous options to protect it. Join Siafoo Now or Learn More

Fast Improved Perlin Noise Atom Feed 0

In Brief A NumPy rewrite of JD Marble's 2D Improved Perlin Noise Python snippet. This version is roughly 3 to 10 times faster than the pure Python version above but it does require NumPy.... more
# 's
 1from numpy import array, abs, arange, dot, int8, int32, floor, fromfunction,\
2 hypot, ones, prod, random, indices, newaxis, poly1d
3import Image
4
5class PerlinNoise(object):
6
7 def noise(self, coords):
8
9 ijk = (floor(coords) + self.idx_ar).astype(int8)
10
11 uvw = coords - ijk
12
13 indexes = self.P[ijk[:,:, self.order - 1]]
14
15 for i in range(self.order - 1):
16 indexes = self.P[(ijk[:,:, i] + indexes) % len(self.P)]
17
18 gradiens = self.G[indexes % len(self.G)]
19# gradiens = self.G[(ijk[:,:, 0] + indexes) % len(self.G)]
20
21 res = (self.drop(abs(uvw)).prod(axis=2)*prod([gradiens, uvw], axis=0).sum(axis=2)).sum(axis=1)
22
23 res[res > 1.0] = 1.0
24 res[res < -1.0] = -1.0
25
26 return ((res + 1)*128).astype(int8)
27
28 def getData(self, scale=32.0):
29 return self.noise(indices(self.size).reshape(self.order, 1, -1).T / scale)
30
31 def getImage(self, scale=32.0):
32 return Image.frombuffer('L', self.size[:2],
33 self.getData(scale)[ : self.size[0]*self.size[1]],
34 'raw', 'L', 0, 1)
35
36 def saveImage(self, fileName, scale=32.0):
37 im = self.getImage(scale)
38 im.save(fileName)
39
40 def __init__(self, size=None, n=None):
41
42 n = n if n else 256
43 self.size = size if size else (256, 256)
44
45 self.order = len(self.size)
46
47 # Generate WAY more numbers than we need
48 # because we are throwing out all the numbers not inside a unit
49 # sphere. Something of a hack but statistically speaking
50 # it should work fine... or crash.
51 G = (random.uniform(size=2*self.order*n)*2 - 1).reshape(-1, self.order)
52
53 # GAH! How do I generalize this?!
54 #length = hypot(G[:,i] for i in range(self.order))
55
56 if self.order == 1:
57 length = G[:,0]
58 elif self.order == 2:
59 length = hypot(G[:,0], G[:,1])
60 elif self.order == 3:
61 length = hypot(G[:,0], G[:,1], G[:,2])
62
63 self.G = (G[length < 1] / (length[length < 1])[:,newaxis])[:n,]
64 self.P = arange(n, dtype=int32)
65
66 random.shuffle(self.P)
67
68 self.idx_ar = indices(2*ones(self.order), dtype=int8).reshape(self.order, -1).T
69 self.drop = poly1d((-6, 15, -10, 0, 0, 1.0))
70
71if __name__ == "__main__":
72 # 1D Noise
73 n = PerlinNoise(size=(1, 128))
74 n.saveImage('PerlinNoise-1D.png')
75
76 # 2D Noise
77 n = PerlinNoise(size=(128, 128))
78 n.saveImage('PerlinNoise-2D.png')
79
80 # 3D Noise
81 # It is preferable to get the 3D noise data and manipulate it yourself
82 # since saving it as an image might have some strange results (for non-1 3d dimenison
83 n = PerlinNoise(size=(128, 128, 1))
84 n.saveImage('PerlinNoise-3D.png')

A NumPy rewrite of JD Marble's 2D Improved Perlin Noise Python snippet. This version is roughly 3 to 10 times faster than the pure Python version above but it does require NumPy.

The code supports 1D, 2D and 3D noise... it should be fairly easy to extend it to higher dimensions.

Warning

Be careful with 3D noise, it's fairly memory intensive

For more information about Perlin noise, check out Making Noise and Matt Zucker's excellent Perlin noise math FAQ

In the following picture, the 3D noise values are used to lookup colours from a transfer function and the whole thing is rendered using the wxPython and PyOpenGL Volume Rendering Skeleton

Two examples of volume rendered 3D noise.

Comments

over 7 years ago (15 Nov 2008 at 08:12 AM) by impiaaa
You should make it N-Dimensional, not just 2D or 3D. That would be really cool.
over 7 years ago (15 Nov 2008 at 10:45 AM) by Stou S.
I am working on it =)