8

I am doing an experiment and attempting to improve the max particle count before frame-rates start to drop in HTML5 Canvas.

I'm using requestAnimationFrame, I'm using drawImage from a canvas as this seems to be the fastest method for rendering images (as tested on jsPerf).

There's a working jsFiddle here: http://fiddle.jshell.net/bewYC/5/

You might have to refresh or re-run a few times to get it to work (no idea why but it just doesn't want to run on the first page load.)

As is, my computer running Chrome 22 can maintain 60FPS with about 5,000 particles. With every step above that, FPS starts to drop. If I remove drawImage() and just calculate the particles' positions, my processor doesn't max out until well over 10X as many particles.

What I want to know: Is there is a faster way to render a large amount of particles (say 40,000 for example) than using a loop with drawImage in it? I especially want to know this about JavaScript/Canvas, but if you only have knowledge about another language such as Java or C#, then please share anyway.

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
BumbleShrimp
  • 2,150
  • 23
  • 42
  • 1
    In my experience, 5,000 particles at 60fps in Canvas is pretty damn good. If you're not adverse to WebGL, then [WebGL2D](https://github.com/gameclosure/webgl-2d) is very likely a simple drop in and should yield much better performance. I have also found that recent versions of Firefox seem to perform better with `drawImage` than Chrome does. – Matt Greer Nov 15 '12 at 19:55
  • For what it's worth, my simple, largely unoptimized [particle editor](http://city41.github.com/particle.js/v2/) can't get nearly that good of performance. But, I am not just using `drawImage`, I am rendering to an off screen buffer and using `source-atop` which is very expensive. – Matt Greer Nov 15 '12 at 19:57
  • It's a fast computer, and I've used every kind of optimization I've been able to find so far. For instance, `clearRect` instead of drawing a new background, using `drawImage` instead of `fillRect` or `putImagedata`. Drawing with `drawImage` from another canvas is faster than drawing from an actual image object, etc. Mostly I think the 5,000 can just be accredited to my 2600k running at 4.8ghz. – BumbleShrimp Nov 15 '12 at 19:58
  • Those all sound like good changes to me. I dunno, canvas still isn't all *that* performant, sadly. btw, your fiddle doesn't work most of the time because you need to wait for the image to load before proceeding. I also had to switch to a different image as I kept getting a 403: http://fiddle.jshell.net/bewYC/7/ – Matt Greer Nov 15 '12 at 20:03
  • @MattGreer Thank you for pointing out the image loading! That was bugging me big time but I just ignored it. I wouldn't really try to implement a particle engine of 50,000 particles in a game on Canvas, I know there are better options, I just wanted to see if I could push it farther for fun. – BumbleShrimp Nov 15 '12 at 20:08

1 Answers1

10

For this problem, using WebGL (or other “3D” API as appropriate for your platform) is nearly always the best way to do it. Compositing lots of images ("textures", rather) at moving positions is exactly what graphics hardware is designed to be good for. Modern browsers do use GPU acceleration for performing 2D-Canvas drawing operations, but there is still JavaScript requesting the drawing of each individual image, and that's the problem.

I recommend you check out WebGL — for simple things like a particle system it's not hard to program at all, and you can easily render thousands of particles. Your JavaScript simply provides an array containing the positions of all the particles.

An advanced technique is to put the simulation of the particles as well on the GPU, thus requiring no JavaScript to execute per-particle at all. I have myself written a GPU particle simulator in my GLToy. Here it's configured for 80,000 particles and that achieves 60 FPS on my laptop. In fact, the limitation in that particular configuration is the fill-rate of the smooth particles; if we just use points I can push it up to 300,000 particles. And I am no wizard of graphics programming; I'm sure someone who knows exactly what to do could push it further.

(P.S. links may be fragile as I revise GLToy; if you don't get the named effects please let me know so I can fix the links.)

Kevin Reid
  • 37,492
  • 13
  • 80
  • 108