How to Generate Pseudorandom Noise

How to Generate Pseudorandom Noise#

Pseudo-random noise functions can create sequences of numbers that seem random and unpredictable but are actually generated by repeatable, deterministic processes. These algorithms can be useful for various goals such as generating random textures and animating digital characters moving across the screen.

This library provides two algorithms for you to use to generate noise: the OpenSimplex algorithm and the Processing Noise algorithm.

Noise generation is a rich and complex subject that academics and researchers have been studying for decades. The noise functionality provided by py5 only scratches the surface of what is possible. You are encouraged to do your own research and experimentation to learn more.

Below is an overview of how to use py5’s noise generation methods.

OpenSimplex2 Noise#

The first choice is KdotJPG’s OpenSimplex2 algorithm. Specifically, the OpenSimplex2S (SuperSimplex) algorithm. The OpenSimplex algorithm was created in response to the copyright restrictions surrounding the use of Ken Perlin’s simplex noise algorithm.

Below is an example of how to use the Sketch.os_noise() method:

os_noise(1.1, 2.2)
-0.517877995967865

OpenSimplex noise values will always be between -1 and 1.

The method can accept 2, 3, or 4 parameters to create 2D, 3D, or 4D noise.

os_noise(1.1, 2.2, 3.3)
0.17793048918247223
os_noise(1.1, 2.2, 3.3, 4.4)
0.6522994041442871

To generate 1D noise, add your favorite constant value as a second parameter.

If you like, you can initialize the OpenSimplex noise generator with a seed value using Sketch.os_noise_seed(). This will ensure that your code generates the same noise values every time your Sketch is run. By default, py5 randomly picks a seed value for you when the Sketch starts running. Therefore the noise values will not be the same from one Sketch to the next.

os_noise_seed(42)

os_noise(1.1, 2.2)
-0.4431585669517517

The Sketch.os_noise() method can accept numpy arrays as parameters. This will be dramatically faster than repeatedly calling the method in a for loop. Calling this method repeatedly in a for loop should be avoided whenever possible.

import numpy as np

a = np.linspace(0, 1, num=4)
b = np.linspace(10, 20, num=4)

os_noise(a, b)
array([-0.6399585 , -0.44705582,  0.0124972 ,  0.462501  ], dtype=float32)

If the array parameters are different shapes but can be broadcast together, py5 will do the broadcasting for you and return the appropriate results.

import numpy as np

a = np.linspace(0, 1, num=3)
b = np.linspace(0, 1, num=4)[:, None]

print(a.shape)
print(b.shape)
(3,)
(4, 1)
out = os_noise(a, b)

print(out.shape)

out
(4, 3)
array([[ 1.4474716e-28, -2.5384188e-01,  3.4994957e-01],
       [-2.2073200e-01,  1.7000672e-01,  6.1272073e-01],
       [ 3.5158262e-01, -3.7297922e-01,  7.9941893e-01],
       [-1.8971356e-02,  7.7302456e-02,  5.9759218e-01]], dtype=float32)

Here’s a quick example of how this can be used in a Sketch to create 2D noise.

%%py5bot
size(500, 400)

x, y = np.meshgrid(np.linspace(0, 10, num=width), np.linspace(0, 10, num=height))
out = remap(os_noise(x, y), -1, 1, 0, 255)
img = create_image_from_numpy(out, bands='L')

image(img, 0, 0)
../_images/024e61e0eadbf1018bec62345d7a3ad175c2327e48b3f523c63bcc186ea0a98d.png

Processing Noise#

The second choice is Processing’s noise algorithm. These noise values will be identical to Processing’s for the same input parameters. This algorithm is unique to Processing and has been used by countless artists and creative coders over the years for their projects.

Below is an example of how to use the Sketch.noise() method:

noise(1.1)
0.7261937260627747

Processing noise values will typically be between 0 and 1. By default it will always be within this range but can exceed it with some configurations of Sketch.noise_detail().

The method can accept 1, 2, or 3 parameters to create 1D, 2D, or 3D noise.

noise(1.1, 2.2)
0.2721487879753113
noise(1.1, 2.2, 3.3)
0.455109566450119

Much like the OpenSimplex algorithm, you can set a noise seed to make the noise values repeatable every time your Sketch is run. By default the noise values will not be the same from one Sketch to the next.

noise_seed(42)

noise(1.1, 2.2)
0.4222339689731598

The Processing noise algorithm is configurable in that you can adjust the number of noise “octaves” and the amplitude of the octaves. You should read the Sketch.noise_detail() documentation and do your own experimentation to fully understand what the options are.

noise_detail(7, 0.2)

noise(1.1, 2.2)
0.22393010556697845

Like the OpenSimplex algorithm, you can pass numpy arrays to Sketch.noise() that will be broadcast to the proper shapes if need be. Passing arrays will always be significantly faster than calling this method repeatedly in a loop.

import numpy as np

a = np.linspace(0, 1, num=3)
b = np.linspace(0, 1, num=4)[:, None]

print(a.shape)
print(b.shape)
(3,)
(4, 1)
out = noise(a, b)

print(out.shape)

out
(4, 3)
array([[0.45472148, 0.2165364 , 0.10492641],
       [0.39262062, 0.30076867, 0.21060048],
       [0.30914652, 0.35280144, 0.38747144],
       [0.2749675 , 0.34987056, 0.4797618 ]], dtype=float32)

Here’s another quick example of how this can be used in a Sketch to create 2D noise. Observe that the visual characteristics of this noise is different from the similar Sketch created with OpenSimplex.

%%py5bot
size(500, 400)

x, y = np.meshgrid(np.linspace(0, 10, num=width), np.linspace(0, 10, num=height))
out = remap(noise(x, y), 0, 1, 0, 255)
img = create_image_from_numpy(out, bands='L')

image(img, 0, 0)
../_images/c7272e0288f6b52924fbad9d1ba72b3424ec7948f324e3288d67c0c52805a504.png

Other Noise Options#

If neither of Sketch.noise() nor Sketch.os_noise() meet your needs, there are other Python libraries available that you can consider instead.

  • noise: Previous versions of py5 used this library to provide Perlin Noise and Simplex Noise algorithms. The library uses compiled c code to generate the noise values. It works well but has a few bugs, one of which can cause a py5 Sketch to suffer a segmentation fault. Unfortunately the library has not had a release in years so the bugs are not likely to be fixed. For these reasons and a few others, py5 can’t have this library as a dependency and was removed. However, you may find it useful to install this library on your own if you want to use Perlin noise.

  • vec-noise: Haven’t actually used this one much but it seems to be a better and faster version of the preivously mentioned noise library.

  • vnoise: Pure Python implementation of Ken Perlin’s Improved Noise function. Seems to be a well maintained library. This library was seriously considered as a possible replacement for the original noise library but the noise calculations are very slow.

  • opensimplex: Pure Python implementation of the OpenSimplex algorithm. If you install the optional dependency Numba, this library will be significantly faster than py5’s open simplex implementation.

  • UniformNoise: If you are willing to setup and work with a Java library, give the Uniform Noise library a try. The generated values will be uniformly distributed between 0 and 1.

  • FastNoiseLite: Another Java library that is worth considering is FastNoiseLite. If nothing else, you can experiment with the GUI to learn more about the vast ecosystem of noise algorithms that are available.

Each of these noise algorithms have their own strengths, weaknesses, and idiosyncrasies. Explore and experiment to learn more.