Created
January 8, 2010 10:34
-
-
Save kerspoon/271967 to your computer and use it in GitHub Desktop.
simple perlin noise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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