Go Down

### Topic: Perlin Noise Generator (Read 3955 times)previous topic - next topic

#### Mike Edwards

##### Oct 07, 2007, 04:53 pm
Hey all!

If you've worked with computer graphics, you've probably run across Perlin Noise before.  It's great for making clouds and other textures.  It's also a nice way to add the illusion of life to motion, etc. in a way that's a lot less random than, well, random().

I wrote the following Perlin Noise generator for the Arduino.  Now all the fun of Processing's noise() function is at your command on the chip!

Any additions, changes, corrections, etc. are highly appreciated.  And DEFINITELY let me know if you use this for something cool!

See:
http://freespace.virgin.net/hugo.elias/models/m_perlin.html

for the source of the algorithm I implemented and a great walkthrough of how to use it.

Code: [Select]
/*

This program is free software; you can redistribute it and/or modify
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
*/
#include <math.h>

float x1,y1,x2,y2,persistence;
int octaves;

void setup()
{
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
analogWrite(5,0);
analogWrite(6,0);
//persistence affects the degree to which the "finer" noise is seen
persistence = 0.25;
//octaves are the number of "layers" of noise that get computed
octaves = 3;
}

void loop()
{
x1 = float(millis())/100.0f;
y1 = 10.0f;
x2 = float(millis())/100.0f;
y2 = 11.0f;

//PerlinNoise2 results in a float between -1 and 1
//below we convert to a n int between 0 and 255
int m = int(PerlinNoise2(x1,y1,persistence,octaves)*128+128);
int n = int(PerlinNoise2(x2,y2,persistence,octaves)*128+128);

analogWrite(5,m);
analogWrite(6,n);
delay(5);
}

//using the algorithm from http://freespace.virgin.net/hugo.elias/models/m_perlin.html
// thanks to hugo elias
float Noise2(float x, float y)
{
long noise;
noise = x + y * 57;
noise = pow(noise << 13,noise);
return ( 1.0 - ( long(noise * (noise * noise * 15731L + 789221L) + 1376312589L) & 0x7fffffff) / 1073741824.0);
}

float SmoothNoise2(float x, float y)
{
float corners, sides, center;
corners = ( Noise2(x-1, y-1)+Noise2(x+1, y-1)+Noise2(x-1, y+1)+Noise2(x+1, y+1) ) / 16;
sides   = ( Noise2(x-1, y)  +Noise2(x+1, y)  +Noise2(x, y-1)  +Noise2(x, y+1) ) /  8;
center  =  Noise2(x, y) / 4;
return (corners + sides + center);
}

float InterpolatedNoise2(float x, float y)
{
float v1,v2,v3,v4,i1,i2,fractionX,fractionY;
long longX,longY;

longX = long(x);
fractionX = x - longX;

longY = long(y);
fractionY = y - longY;

v1 = SmoothNoise2(longX, longY);
v2 = SmoothNoise2(longX + 1, longY);
v3 = SmoothNoise2(longX, longY + 1);
v4 = SmoothNoise2(longX + 1, longY + 1);

i1 = Interpolate(v1 , v2 , fractionX);
i2 = Interpolate(v3 , v4 , fractionX);

return(Interpolate(i1 , i2 , fractionY));
}

float Interpolate(float a, float b, float x)
{
//cosine interpolations
return(CosineInterpolate(a, b, x));
}

float LinearInterpolate(float a, float b, float x)
{
return(a*(1-x) + b*x);
}

float CosineInterpolate(float a, float b, float x)
{
float ft = x * 3.1415927;
float f = (1 - cos(ft)) * .5;

return(a*(1-f) + b*f);
}

float PerlinNoise2(float x, float y, float persistance, int octaves)
{
float frequency, amplitude;
float total = 0.0;

for (int i = 0; i <= octaves - 1; i++)
{
frequency = pow(2,i);
amplitude = pow(persistence,i);

total = total + InterpolatedNoise2(x * frequency, y * frequency) * amplitude;
}

return(total);
}

#### hungerburg

#1
##### Oct 08, 2007, 09:43 am
Funny, I did that too, just weeks ago, its running fine for days and produces great curves... This (Kens) one could some time be part of gnu math.h, couldn't it? Somehow I cant get the formatting ok, does the board software unexpand blanks?

Code: [Select]

#include <math.h>

/*
Ken Perlins improved noise   -  http://mrl.nyu.edu/~perlin/noise/
C-port:  http://www.fundza.com/c4serious/noise/perlin/perlin.html
by Malcolm Kesson;   arduino port by Peter Chiochetti, Sep 2007 :
-  make permutation constant byte, obsoletes init(), lookup % 256
*/

static const byte p[] = {   151,160,137,91,90, 15,131, 13,201,95,96,
53,194,233, 7,225,140,36,103,30,69,142, 8,99,37,240,21,10,23,190, 6,
148,247,120,234,75, 0,26,197,62,94,252,219,203,117, 35,11,32,57,177,
33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,
48,27,166, 77,146,158,231,83,111,229,122, 60,211,133,230,220,105,92,
41,55,46,245,40,244,102,143,54,65,25,63,161, 1,216,80,73,209,76,132,
187,208, 89, 18,169,200,196,135,130,116,188,159, 86,164,100,109,198,
173,186, 3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,
212,207,206, 59,227, 47,16,58,17,182,189, 28,42,223,183,170,213,119,
248,152,2,44,154,163,70,221,153,101,155,167,43,172, 9,129,22,39,253,
19,98,108,110,79,113,224,232,178,185,112,104,218,246, 97,228,251,34,
242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,
150,254,138,236,205, 93,222,114, 67,29,24, 72,243,141,128,195,78,66,
215,61,156,180
};

double fade(double t){ return t * t * t * (t * (t * 6 - 15) + 10); }
double lerp(double t, double a, double b){ return a + t * (b - a); }
double grad(int hash, double x, double y, double z)
{
int     h = hash & 15;          /* CONVERT LO 4 BITS OF HASH CODE */
double  u = h < 8 ? x : y,      /* INTO 12 GRADIENT DIRECTIONS.   */
v = h < 4 ? y : h==12||h==14 ? x : z;
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
}

#define P(x) p[(x) & 255]

double pnoise(double x, double y, double z)
{
int   X = (int)floor(x) & 255,             /* FIND UNIT CUBE THAT */
Y = (int)floor(y) & 255,             /* CONTAINS POINT.     */
Z = (int)floor(z) & 255;
x -= floor(x);                             /* FIND RELATIVE X,Y,Z */
y -= floor(y);                             /* OF POINT IN CUBE.   */
z -= floor(z);
v = fade(y),                       /* FOR EACH OF X,Y,Z.  */
int  A = P(X)+Y,
AA = P(A)+Z,
AB = P(A+1)+Z,                        /* HASH COORDINATES OF */
B = P(X+1)+Y,
BA = P(B)+Z,
BB = P(B+1)+Z;                        /* THE 8 CUBE CORNERS, */

grad(P(BA  ), x-1, y, z)),   /* BLENDED */
lerp(u, grad(P(AB  ), x, y-1, z),        /* RESULTS */
grad(P(BB  ), x-1, y-1, z))),       /* FROM  8 */
lerp(v, lerp(u, grad(P(AA+1), x, y, z-1),  /* CORNERS */
grad(P(BA+1), x-1, y, z-1)),          /* OF CUBE */
}

#define ledPin 13

{
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
delay(dur);
digitalWrite(ledPin, LOW);
}

void setup()
{
Serial.begin(19200);
}

/* Koordinatenpaare rechnen */
void loop()
{
double x, y;
static double i = 0;

i += 0.01;
// aktuelle Iteration ausgeben
Serial.print("# ");
Serial.println((long)(i*100));

// nÃ¤chsten Punkt berechnen
x = pnoise(i+sin(i), i+cos(i), i);
y = pnoise(i-sin(i), i-cos(i), i);

// aktuelle Koordinaten ausgeben
Serial.print(x);
Serial.print(" ");
Serial.println(y);
}

Go Up

Please enter a valid email to subscribe