In [2]:
import numpy as np
import matplotlib.pyplot as plt
import noise
import perlin
%matplotlib inline

linear interpolation

We need a function ${f}$ that, given values ${v_0}$ and ${v_1}$ and some interval ${t}$ where $0 \le {t} \le 1$, returns an interpolated value between ${v_0}$ and ${v_1}$.

The best way to start is with linear interpolation and that's what the lerp function does.

Let's assume we have to values ${v_0}$ and ${v_1}$:


In [20]:
v0 = 2
v1 = 5
plt.plot([0, 1], [v0, v1], '--')
t = 1.0 / 3
vt = noise.lerp(v0, v1, t)
plt.plot(t, vt, 'ro')


Out[20]:
[<matplotlib.lines.Line2D at 0x7628100c50>]

smoothstep


In [5]:
x = np.linspace(0, 1.0)
y1 = noise.ss3(x)
y2 = noise.ss5(x)
plt.plot(x, y1, label="smooth")
plt.plot(x, y2, label="smoother")
plt.legend(loc=2)


Out[5]:
<matplotlib.legend.Legend at 0x762f5d29b0>

vectors


In [6]:
class Vector:
    def __init__(self, *components):
        self.components = np.array(components)
        
    def mag(self):
        return np.sqrt(sum(self.components**2))
        
    def __len__(self):
        return len(self.components)
    
    def __iter__(self):
        for c in self.components:
            yield c

seeding


In [7]:
np.random.ranf((2,3,2,2)) # seed in n-dimensions


Out[7]:
array([[[[ 0.84900876,  0.15708229],
         [ 0.07517729,  0.89937132]],

        [[ 0.35796972,  0.68400978],
         [ 0.77060091,  0.83516851]],

        [[ 0.54120818,  0.47229802],
         [ 0.12517188,  0.4401293 ]]],


       [[[ 0.99143527,  0.09214633],
         [ 0.01947407,  0.50723066]],

        [[ 0.56071254,  0.07413207],
         [ 0.76308961,  0.77440445]],

        [[ 0.8371608 ,  0.07340915],
         [ 0.8018981 ,  0.80268589]]]])

noise field

For instance, to create a hypercube of noise we could do something like this:


In [8]:
c4 = noise.Field(d=(8,8,8,8), seed = 5)

We can plot any course through this field, for example:


In [9]:
q = np.arange(0, 8)
x = [c4(x, 0, 0, 0) for x in q]
y = [c4(0, y, 0, 0) for y in q]
plt.plot(q, x, 'bo')
plt.plot(q, y, 'ro')


Out[9]:
[<matplotlib.lines.Line2D at 0x762f35f780>]

We could render a graph but that would be like cheating. We would be using the matplotlib linear interpolation instead of our own:


In [10]:
# a one-dimensional noise field of 8 samples
c1 = noise.Field(d=(8,))
x = np.linspace(0, 7, 8)
y = [c1(x) for x in x]
# this will use matplotlib interpolation and not ours
plt.plot(x, y)


Out[10]:
[<matplotlib.lines.Line2D at 0x762f6bfac8>]

We can do better though by using one of the smoothstep functions. Instead of calculating ${v_t}$ directly we can do some tricks on ${t}$ to modify the outcome.

For convience let's start with the ss3 function and plot it so we know what it looks like:


In [11]:
x = np.linspace(0, 1.0, 100)
y = noise.ss3(x)
plt.plot(x, y)


Out[11]:
[<matplotlib.lines.Line2D at 0x762f720470>]

Now we setup a noise field and define a helper function noise1 in order to get our coherent noise.


In [12]:
samples = 32
gen = noise.Field(d=(samples,))

def noise1(x, curve = lambda x: x):
    xi = int(x)
    xmin = xi % samples
    xmax = 0 if xmin == (samples - 1) else xmin + 1
    t = x - xi
    return noise.lerp(gen(xmin), gen(xmax), curve(t))

x = np.linspace(0, 10, 100)
y1 = [noise1(x) for x in x]
y2 = [noise1(x, noise.ss5) for x in x]
plt.plot(x, y1, '--')
plt.plot(x, y2)


Out[12]:
[<matplotlib.lines.Line2D at 0x762f6f6d30>]

fbm noise


In [21]:
x = np.linspace(0, 4, 100)
y1 = [1.0 * perlin.noise2d(x, 0) for x in x]
y2 = [0.5 * perlin.noise2d(x * 2, 0) for x in x]
y3 = [0.25 * perlin.noise2d(x * 4, 0) for x in x]
y4 = [0.125 * perlin.noise2d(x * 8, 0) for x in x]
plt.plot(x, y1)
plt.plot(x, y2)
plt.plot(x, y3)
plt.plot(x, y4)


Out[21]:
[<matplotlib.lines.Line2D at 0x76281f5e10>]

In [18]:
x = np.linspace(0, 4, 100)
y = [perlin.fbm(x, 0) for x in x]
plt.plot(x, y)


Out[18]:
[<matplotlib.lines.Line2D at 0x76309caf60>]

In [ ]: