Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
simple perlin noise
#! /usr/local/bin/python
# simple perlin noise
#------------------------------------------------------------------------------
# Copyright (C) 2009 James Brooks (kerspoon)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 dated June, 1991.
#
# This software is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANDABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#------------------------------------------------------------------------------
import random
import math
"""
Made by James Brooks - http://kerspoon.com/
This is a very simple perlin noise generator. Strictly speaking is doesn't
use the same formula as Ken Perlin version but it good enough and
illustrates the principle. This is not optimised at all.
Usage
-----
perlin_1d(2.0, 10, 1000)
persistance -> float -> factor by which the amplitude changes per octave
octaves -> int -> the number of layers to add*
length -> int -> the length of the returned array
* each layer has twice the amplitude as the previous
To Add
------
1. By interpolating between the last and first element in `perlin_layer`
we can have a smoothly looping list.
2. We can make 2d points and interpolate to make 2d noise.
"""
def find(pred, seq):
"""Return first item in sequence where pred(item) == True."""
for item in seq:
if pred(item):
return item
assert find(lambda x: x>4, range(100)) == 5
assert find(lambda x: x>8 and (x%4 == 0), range(100)) == 12
def find2(pred, seq):
"""Return index in sequence where pred(item) == True."""
for idx, item in enumerate(seq):
if pred(item):
return idx
def zeros(length):
"""an array of given length where each item is zero"""
return [0 for _ in range(length)]
assert zeros(1) == [0]
assert zeros(3) == [0,0,0]
def random_list(amplitude, length):
"""an array of given length where each item is a uniform
random number in the range (0, amplitude)."""
return [random.uniform(0, amplitude) for _ in range(length)]
assert len(random_list(1.0, 100)) == 100
assert len(random_list(1.0, 99)) == 99
def add_lists(a, b):
"""element wise adding of lists"""
return [x+y for x,y in zip(a, b)]
assert add_lists([1],[2]) == [3]
assert add_lists([1, 4], [2, 8]) == [3, 12]
assert add_lists([-1, 3, 1, 1], [2, 6]) == [1, 9]
def linear_interpolate(a, b, x):
"""
lerp: a, b are the values of the two end points
x is the location between those end point that
you want the value of"""
return a*(1.0-x) + b*x
def cosine_interpolate(a, b, x):
"""
lerp: a, b are the values of the two end points
x is the location between those end point that
you want the value of"""
f = (1 - math.cos(x * math.pi)) / 2.0
return a*(1.0-f) + b*f
def perlin_layer(amplitude, length, datapoints):
interpolate = cosine_interpolate
rnd = random_list(amplitude, datapoints)
result = zeros(length)
step_size = float(length) / (datapoints - 1.0)
lookup = [step_size*n for n in range(datapoints)]
for n in range(length):
idx = find2(lambda x: float(n) < x, lookup)
location = abs(lookup[idx-1] - n) / step_size
result[n] = interpolate(rnd[idx-1], rnd[idx], location)
return result
def perlin_1d(persistance, octaves, length):
datapoints = 10
amplitude = 1.0
result = zeros(length)
for _ in range(octaves):
res = perlin_layer(amplitude, length, datapoints)
result = add_lists(result, res)
amplitude /= 2.0
datapoints = int(datapoints * persistance)
return result
for x in perlin_1d(2.0, 10, 1000):
print x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.