Canvas Perlin Noise
I recently decided to get some Perlin noise up and running in javascript. I set out looking for something to port, I found a few interesting articles and a few Perlin noise implementations already in javascript. But in the end I went with porting “improved noise” from Ken Perlin’s website : http://mrl.nyu.edu/~perlin/noise/.
Here is a demo:
Here is the noise function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | // IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN. (function(){ var p = []; var permutation = [ 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]; for (var i=0; i < 256 ; i++) p[256+i] = p[i] = permutation[i]; function noise(x, y, z) { var X = Math.floor(x) & 255, Y = Math.floor(y) & 255, Z = Math.floor(z) & 255; x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z); var u = fade(x), v = fade(y), w = fade(z); var 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-1, y , z )), lerp(u, grad(p[AB ], x , y-1, z ), grad(p[BB ], x-1, y-1, z ))), lerp(v, lerp(u, grad(p[AA+1], x , y , z-1 ), grad(p[BA+1], x-1, y , z-1 )), lerp(u, grad(p[AB+1], x , y-1, z-1 ), grad(p[BB+1], x-1, y-1, z-1 )))); } function fade(t) { return t * t * t * (t * (t * 6 - 15) + 10); } function lerp(t, a, b) { return a + t * (b - a); } function grad(hash, x, y, z) { var h = hash & 15; var 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); } window.noise = noise; })(); |
and here is the code for the demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title></title> <script src="http://code.jquery.com/jquery-latest.min.js"></script> <script src="perlin_noise.js"></script> <script> $(function(){ var canvas = $("<canvas>").appendTo("body")[0]; canvas.width = canvas.height = 200; var c = canvas.getContext("2d"); c.fillStyle = "black"; c.fillRect(0,0,canvas.width,canvas.height); var pix = c.createImageData(canvas.width, canvas.height); var inc = 0; var freq = 1/20; var z = 0; setInterval(function(){ z += 0.02; inc = 0; for (var y = 0; y < canvas.height; y++) { for (var x = 0; x < canvas.width; x++) { var col = parseInt(Math.abs(noise(x * freq,y * freq, z)) * 500); pix.data[inc++] = col; pix.data[inc++] = col; pix.data[inc++] = col; pix.data[inc++] = 255; } } c.putImageData(pix, 0, 0); }, 30); }); </script> <style> body,html{ margin : 0px; padding : 0px; } </style> </head> <body></body> </html> |