Update: I would recommend using the noise functions in the FastLED library if you’d like to use Perlin Noise on an Arduino. Their algorithms are highly optimised for use on Arduino.
I’ve implemented the Improved Noise example for Arduino. Originally this is developed for a light installation, however the example below shows the effect (and the time it takes) in the Serial monitor.
Configure the monitor for 57600 Baud. It takes about 12ms to render the noise for 50 lights (about 4ms for 20 lights). In an earlier post on the Arduino forum I used another implementation, that one took 7ms for 20 lights.
/* Perlin improved noise implementation for Arduino Fixed Point http://mrl.nyu.edu/~perlin/noise/INoise.java Changed the lookup tables with prerendered to store in Program memory. Otherwise Arduino has a memory shortage. copyleft kasperkamperman.com 15-12-2013 */ #include <avr/pgmspace.h> // permutation array PROGMEM prog_uchar 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, }; // array below generated with this code line in the INoise code. // static { for (int i=0; i < 256 ; i++) fade[i] = (int)((1<<12)*f(i/256.)); } PROGMEM prog_uint16_t fadeArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 3, 4, 6, 7, 9, 10, 12, 14, 17, 19, 22, 25, 29, 32, 36, 40, 45, 49, 54, 60, 65, 71, 77, 84, 91, 98, 105, 113, 121, 130, 139, 148, 158, 167, 178, 188, 199, 211, 222, 234, 247, 259, 273, 286, 300, 314, 329, 344, 359, 374, 390, 407, 424, 441, 458, 476, 494, 512, 531, 550, 570, 589, 609, 630, 651, 672, 693, 715, 737, 759, 782, 805, 828, 851, 875, 899, 923, 948, 973, 998, 1023, 1049, 1074, 1100, 1127, 1153, 1180, 1207, 1234, 1261, 1289, 1316, 1344, 1372, 1400, 1429, 1457, 1486, 1515, 1543, 1572, 1602, 1631, 1660, 1690, 1719, 1749, 1778, 1808, 1838, 1868, 1898, 1928, 1958, 1988, 2018, 2048, 2077, 2107, 2137, 2167, 2197, 2227, 2257, 2287, 2317, 2346, 2376, 2405, 2435, 2464, 2493, 2523, 2552, 2580, 2609, 2638, 2666, 2695, 2723, 2751, 2779, 2806, 2834, 2861, 2888, 2915, 2942, 2968, 2995, 3021, 3046, 3072, 3097, 3122, 3147, 3172, 3196, 3220, 3244, 3267, 3290, 3313, 3336, 3358, 3380, 3402, 3423, 3444, 3465, 3486, 3506, 3525, 3545, 3564, 3583, 3601, 3619, 3637, 3654, 3672, 3688, 3705, 3721, 3736, 3751, 3766, 3781, 3795, 3809, 3822, 3836, 3848, 3861, 3873, 3884, 3896, 3907, 3917, 3928, 3937, 3947, 3956, 3965, 3974, 3982, 3990, 3997, 4004, 4011, 4018, 4024, 4030, 4035, 4041, 4046, 4050, 4055, 4059, 4063, 4066, 4070, 4073, 4076, 4078, 4081, 4083, 4085, 4086, 4088, 4089, 4091, 4092, 4092, 4093, 4094, 4094, 4095, 4095, 4095, 4095, 4095, 4095, 4095, }; const byte amountOfLights = 50; int lightArray[amountOfLights]; // lightArray is in bytes just values in range of 0 - 255 unsigned long currentTime; // for time measuring purposes unsigned long passedTime; // for time measuring purposes unsigned long longestTime = 0; // for time measuring purposes long perlinTimeInc = 1000L;// 1000; long perlinXInc = 1000L; long perlinYInc = 1000L; unsigned long perlinTimePosition = 0; void setup() { Serial.begin(57600); // while testing 200000 seems like a reasonable maximum // above that the precision gets less perlinTimePosition = 0; //200000; } void loop() { currentTime = micros(); // store current time for(int i=0;i<amountOfLights;i++) { //float x = float(i)*perlinXInc; // input for x value in the renderNoise function long x = i*perlinXInc; //int val = inoise(x, 0, perlinTimePosition); int val = renderNoise(x, 0, perlinTimePosition); lightArray[i] = val; } // go a step further in time (input for y function in perlin noise) perlinTimePosition = perlinTimePosition + perlinTimeInc; // calculate the time the whole calculation took passedTime = micros()-currentTime; // because times will variate, remember the maximum time it took if(passedTime>longestTime) longestTime = passedTime; // print the time it took for the current calculation and the maximum time Serial.print("time: "); Serial.print(passedTime); Serial.print(" max: "); Serial.println(longestTime); Serial.print("array: "); // print the array to see the result // I calculate back to float just for printing purposes // I this way so actually see a perlin effect for(int i=0;i<amountOfLights;i++) { int difference = lightArray[i]; if(difference>127) Serial.print("*"); else Serial.print("-"); } Serial.println(); delay(50); } // returns a value between 0 - 255 for lights int renderNoise(unsigned long x, unsigned long y, unsigned long z) { //return constrain(137 + inoise(x, y, z)>>9, 0, 255); // 127 + 10 zie Processing return 137 + (inoise(x, y, z)>>9); //return 137 + (inoise(x, y, z)/512); } #define P(x) pgm_read_byte_near(p + ((x)&255)) long inoise(unsigned long x, unsigned long y, unsigned long z) { long X = x>>16 & 255, Y = y>>16 & 255, Z = z>>16 & 255, N = 1L<<16; x &= N-1; y &= N-1; z &= N-1; long u=fade(x),v=fade(y),w=fade(z), A=P(X)+Y, AA=P(A)+Z, AB=P(A+1)+Z, B=P(X+1)+Y, BA=P(B)+Z, BB=P(B+1)+Z; return lerp(w, lerp(v, lerp(u, grad(P(AA), x , y , z ), grad(P(BA), x-N , y , z )), lerp(u, grad(P(AB), x , y-N , z ), grad(P(BB), x-N , y-N , z ))), lerp(v, lerp(u, grad(P(AA+1), x , y , z-N ), grad(P(BA+1), x-N , y , z-N )), lerp(u, grad(P(AB+1), x , y-N , z-N ), grad(P(BB+1), x-N , y-N , z-N )))); } long lerp(long t, long a, long b) { return a + (t * (b - a) >> 12); } long grad(long hash, long x, long y, long z) { long h = hash&15, u = h<8?x:y, v = h<4?y:h==12||h==14?x:z; return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); } #define F(x) pgm_read_word_near(fadeArray + (x)) long fade(long t) { long t0 = F(t >> 8), t1 = F(min(255, (t >> 8) + 1)); return t0 + ( (t & 255) * (t1 - t0) >> 8 ); }