Perlin noise in JavaScript comparisons
What started as a simple excersize to put theory to practice has once again spun out of control. Well I’ve just come off three months of programming ActionScript 3 so I needed the distraction (frankly I like js better than as). Plus I never really got into the HTML5 canvas thing and I needed to check that out to. And off course those idiots Apple and Adobe (turning into a bad marriage) are making me feel I should focus on HTML5/js a bit more (doesn’t anybody realize HTML5 isn’t even ready yet?).
After a bit of playing I decided to make a good Perlin noise generator in JavaScript. First I did a quick port from my ActionScript class to JavaScript. But because others had probably preceded me I roamed the web for other implementations. I had to mangle them a bit to get them to work but here they are.
-
sjeiti
url: sjeiti
authors: Ron Valstar and Mario Klingeman
speed: 60 ms -
lonelypinkelephants
url: lonelypinkelephants
author: Jason LaPorte
speed: 10 ms -
bankseanClassical:
url: bankseanClassical:
author: Sean McCullough
speed: 33 ms -
bankseanSimplex:
url: bankseanSimplex:
authors: Sean McCullough and Stefan Gustavson
speed: 22 ms -
slimeland:
url: slimeland:
author: Slime
speed: 34 ms -
processingJs:
url: processingJs:
author: John Resig
speed: 270 ms
The first thing you’ll probably notice that these Perlin noises are all only one octave. Because the banksean and slimeland versions did not implement more octaves I set the others to one octave as well (plus my own quick port had weird artifacts dealing with multiple octaves). I also put in a pseudo random number generator into the ones that used Math.random (we do want to seed it).
I’m a bit disapointed by the one from the one by processingJs. Granted: I did have to hack it a bit to get it to work and from the looks of the comments it’s not fully implemented yet. But it’s still very slow and looks a bit squared.
But the curious one is lonelypinkelephants: 10 milliseconds! It’s even worse that that: running for six octaves it is only three milliseconds slower (see image to the left). And only 50 lines of code! What the fuck dude?! Well, actually it’s a very smart cheat. Where others calculate and store random numbers and then interpolate between these before drawing, the lonelypinkelephants version simply makes a dummy canvas, draws the random numbers and resizes the result onto the final canvas. Letting the interpolation occur somewhere in the native drawImage method. Come to think of it, this may be exactly the reason why Flash’s native Perlin noise function is so much faster than the as3 class.
Unfortunately the lonelypinkelephants version is quite useless for a number of reasons. The first being that the drawImage method is implemented differtly in different browsers. I test all my stuff in Chrome, but I ran the test through Safari just now and the lonelypinkelephants noise looks really different! Secondly, I really want to be able to use x and y offset which is kind of tricky to implement in it’s current form. Lastly we do want that extra dimension (which was exactly the reason I did that Java to as3 port some years ago).
I think I’ll fork the bankseanSimplex version with some octaves and falloff to see if its much faster and prettier than my own quick port. I’ll keep you posted.
To run the tests yourself download code here (and sorry for the mess).
— small update —
On the other hand… well see for yourself… I did the test in four browsers:
-
Chrome
-
Firefox
-
Safari
-
Opera
Isn’t that great?! All of them render differently!!! (yes even Chrome and Firefox). Didn’t I hear something about someone wanting to trade in Flash for HTML5? And look at that (self proclaimed fastest browser) Opera. It looks like it just wraps pixels around the threshold (%). And what’s that first row of pixels doing in the processingJs version?
It looks like I have to do some more figuring out before I decide which noise to use.