# Day 88: Perlin noise

It has been 35 years since Ken Perlin has discovered a technique today called Perlin noise to generate a fixed gradient noise to achieve a better looking textures in the famous movie Tron.

How Perlin noise works?

Look at the top left square at the picture. There are four corners, and each has defined a fixed 2D vector representing gradient, `G¹, G², G³, G⁴`. For any pixel `P` inside we define four vectors representing the difference between the P and each corner, `V¹, V², V³, V⁴`. Finally, we project gradients G onto vectors V and use bilinear interpolation to transform four numbers into one.

Each square on the picture contains 4-times more changes in gradient when compared to the previous square. As the number of changes increases, the output is more and more noisy.

When these 8 images with different frequencies are combined together using [for example] a weighted average, we get quite nice procedural textures.

Non-linear smoothing function and other tricks can be used to get more realistically looking textures. Fire, skies, fluids, landscapes, islands, mountains … Perlin noise and its successors like Simplex noise represent the very basic building block of procedurally generated textures.

https://github.com/coells/100days

https://notebooks.azure.com/coells/libraries/100days

#### algorithm

`def generate_gradient(seed=None):    global gradient        seed and np.random.seed(seed)    gradient = np.random.rand(512, 512, 2) * 2 - 1`
`def perlin_noise(size_x, size_y, frequency):    global gradient        # linear space by frequency    x = np.tile(        np.linspace(0, frequency, size_x, endpoint=False),         size_y    )    y = np.repeat(        np.linspace(0, frequency, size_y, endpoint=False),         size_x    )`
`    # gradient coordinates    x0 = x.astype(int)    y0 = y.astype(int)`
`    # local coordinate    x -= x0    y -= y0`
`    # gradient projections    g00 = gradient[x0, y0]    g10 = gradient[x0 + 1, y0]    g01 = gradient[x0, y0 + 1]    g11 = gradient[x0 + 1, y0 + 1]`
`    # fade    t = (3 - 2 * x) * x * x`
`    # linear interpolation    r = g00[:, 0] * x + g00[:, 1] * y    s = g10[:, 0] * (x - 1) + g10[:, 1] * y    g0 = r + t * (s - r)`
`    # linear interpolation    r = g01[:, 0] * x + g01[:, 1] * (y - 1)    s = g11[:, 0] * (x - 1) + g11[:, 1] * (y - 1)    g1 = r + t * (s - r)`
`    # fade    t = (3 - 2 * y) * y * y`
`    # (bi)linear interpolation    g = g0 + t * (g1 - g0)`
`    # reshape    return g.reshape(size_y, size_x)`
`def banded_perlin_noise(size_x, size_y, frequencies, amplitudes):    image = np.zeros((size_y, size_x))`
`    for f, a in zip(frequencies, amplitudes):        image += perlin_noise(size_x, size_y, f) * a`
`    image -= image.min()    image /= image.max()`
`    return image`

#### run

For full code including plots check the notebook.

`>> generate_gradient(394)>> perlin_noise(8, 8, 1)`
`array([[ 0.  , -0.03, -0.1 , -0.18, -0.23, -0.23, -0.19, -0.11],       [-0.  , -0.04, -0.12, -0.2 , -0.26, -0.27, -0.24, -0.16],       [-0.02, -0.07, -0.15, -0.23, -0.29, -0.31, -0.28, -0.22],       [-0.05, -0.1 , -0.19, -0.27, -0.32, -0.33, -0.31, -0.25],       [-0.06, -0.13, -0.21, -0.28, -0.33, -0.33, -0.31, -0.26],       [-0.07, -0.15, -0.23, -0.28, -0.31, -0.3 , -0.27, -0.23],       [-0.06, -0.15, -0.22, -0.26, -0.27, -0.25, -0.21, -0.16],       [-0.04, -0.13, -0.19, -0.22, -0.21, -0.18, -0.13, -0.08]])`
One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.