# Perlin noise plot with Matplotlib
from pylab import *
import random
XDIM, YDIM = 11, 11 # gradient mesh size
SCALE = 50 # noise grid size per gradient mesh unit size
XDP, YDP = (XDIM - 2) * SCALE + 1, (YDIM - 2) * SCALE + 1
phi = zeros((YDIM, XDIM)) # gradient phase angles
perlin = zeros((YDP, XDP)) # Perlin noise array
# make the plot reproducible by using a fixed random seed
random.seed("Perlin")
# choose random phase angles for gradients
for y in range(YDIM):
for x in range(XDIM):
phi[y,x] = 2 * pi * random.random()
def grad(x0, y0, dx, dy):
"Compute the dot product between the gradient and position vector"
gx, gy = cos(phi[y0,x0]), sin(phi[y0,x0])
return gx * dx + gy * dy
def inter(a, b, w):
"Interpolate between a and b using weight w"
return (b - a) * ((w * (w * 6 - 15) + 10) * w * w * w) + a # smootherstep
#return (b - a) * (3 - 2 * w) * w * w + a # smoothstep
#return (b - a) * w + a # linear
# compute Perlin noise
for yi in range(YDP):
for xi in range(XDP):
x, y = xi / SCALE, yi / SCALE
x0, y0 = int(x), int(y)
dx, dy = x - x0, y - y0
g1 = grad(x0, y0, dx, dy)
g2 = grad(x0 + 1, y0, -1 + dx, dy)
g3 = grad(x0, y0 + 1, dx, -1 + dy)
g4 = grad(x0 + 1, y0 + 1, -1 + dx, -1 + dy)
perlin[yi,xi] = inter(inter(g1, g2, dx), inter(g3, g4, dx), dy)
print(f"Max {perlin.max()}, min {perlin.min()}")
# use Matplotlib to create a plot
figure(figsize = (8, 9))
X = array([x / SCALE for x in range(XDP)])
Y = array([y / SCALE for y in range(YDP)])
imshow(perlin, interpolation = "bicubic", cmap = plt.cm.bwr, vmin = -.8, vmax = .8,
extent = (X.min(), X.max(), Y.max(), Y.min()))
cb = colorbar(orientation = "horizontal")
contour(X, Y, perlin, (0,), linewidths = 2, colors = "green")
xticks(range(XDIM-1), labels = "" * XDIM)
yticks(range(YDIM-1), labels = "" * YDIM)
grid(lw = 1.2, color = "black", alpha = .8, ls = "dashed")
gca().set_position([.1, .2, .8, .8])
cb.ax.set_position([.1, -.68, .8, .8])
title("2-D Perlin noise with contour line at zero")
savefig("perlin_noise_with_contour.svg")
show()