It does depend whether the particles are drawn using shaders or the simpler canvas drawing commands. Without shaders, it would be very CPU intensive. However this site has definitely taken the shader approach.
Particles can be misleading too because if they're simply propagated by some PDE on a regular mesh (or even no mesh) it is an embarrassingly parallel problem. But if they're interacting particles then you need neighbor lists and predictor corrector methods to propagate them which is considerably more difficult to implement and parallelize.
Those guys all interacted with each other and the environment (though the engine was designed to do the interactions in slices, where 1/N of the guys would be checked each frame, but N was not high, like 4 or 5 maybe?)
Just 2 days ago I ran across my all my written notes from GDC 2002 (the only GDC I've gone to; I went by myself for fun) with that specific session, and I had your name written down. (I just thought that was a funny coincidence.) It was very memorable, especially the one with the Doom guy doing the Robotron thing with the camera zooming out. Late last year, Casey Muratori also mentioned it on his handmade hero webcast.
In particle simulations interactions can happen at a distance, so at every time step all particles need to be checked with all other nearby particles to get their distances and compute the force of their interaction. It looks like your simulation is a hard-sphere type interaction where you're only checking to see if two particles bump into each other and is considerably faster to compute.
No, it's not really different from a hard-sphere type interaction. It's the same thing. But that doesn't matter in this context, because in the system we built, our problem was harder/more-general because we were simulating 'guys', meaning you can program an arbitrary interaction into your guys (is guy type X near guy type Y, if so what happens?), and those 'guys' also interacted with a 2D height field terrain.
Keep in mind this was all on computers from the year 2002, which were pretty damn slow compared to computers today. Today you could do a lot of guys.
> though the engine was designed to do the interactions in slices, where 1/N of the guys would be checked each frame, but N was not high, like 4 or 5 maybe?
I'm assuming they all still moved, and the checking was just for change-of-independent-behaviour-pattern?
Yes, everyone moved every frame. If I remember correctly, they would get linearly extrapolated until next time the update for that guy ran. I think there was also an option to do the terrain interaction every frame, to avoid any perception of guys sinking into the terrain slightly.
This three.js demo doesn't seem have dynamically updating particles though, it's essentially rendering static geometry (as far as I can glance from the source).
I did some emscripten/WebGL performance tests a while ago which went into the hundred-thousands particles for 3D-shape-particles at 60fps, but this depends very much on the target hardware, less on the browser or operating system.
Both tests use simple 3D shape particles (5-vertex diamonds) and hardware-instanced rendering (instanced_arrays extension), the first updates particle positions on the CPU, the second on the GPU (fragment shader writes particle position to offscreen render target, which is then sampled in vertex shader to displace particle positions).
The first (CPU updates) goes up to around 450k particles on my Windows7 desktop machine before consistently dropping below 16ms per frame, the second (GPU updates) goes to about 800k particles before dropping below 60fps:
These numbers are not much different then using desktop GL (2.1 with extensions). The real advantages for this type of scenario would come from updating persistently mapped buffers which are not available in WebGL.
What's impressive is the raw math performance of asm.js, the particle update loop is simple glm code (https://github.com/g-truc/glm) without any fancy optimizations.
Running the instancing demo on an iPhone6+ I can get to 150k particles before dropping below 60fps. There's an obvious speed up about three seconds in where I guess the JITter decides to get serious.
So, even though there's no official support for asm.js on mobile safari. It still works surprisingly well!
Try it without instancing. I was working on a rendering approach and initially went with instanced rendering. I was reading about how badly some GPU's handle that, so switched it off and saw a pretty decent perf gain. Basically trading some startup time to mass create the attribute buffers in exchange for better ongoing perf.
Not what you mean, but here's the same demo without instancing and lots of drawcalls, but careful, it will grind your browser to a halt pretty quickly:
This is one uniform update and one draw call per particle in a loop.
Unfortunately draw call overhead on WebGL is really bad compared to desktop GL. On my Windows7/nvidia setup I can go up to about 75k draw calls before frame rate drops below 60fps, on other platforms it's worse. So in this particular (very simple) scenario, hardware instancing actually pays off.
For quad particle systems it is indeed usually better to just directly write the vertices to a dynamic buffer instead of instancing, but I don't have a demo (yet) for this particular case :)
Yeah, definitely keep draw calls low. I'm not surprised to see instancing beating that.
I'd be curious to see your comparison over non instanced/single draw call though. I threw the adapter code I wrote for my instanced version up here if it helps: http://pastebin.com/1gjvreBs
I was expecting the particles to be done as a pure shader implementation, but when I looked at the source that's not the case. While a vertex shader is used to display the particles, the "physics" is done in a JavaScript loop.
This also surprised me. You can do the exact same thing, but with millions of particles, if you store and process them on the GPU. The first example of that technique being used in WebGL is probably by Mr.doob [1]. Since then, there have been many iterations, some of which are basically a cooler version of the linked demo [2]. (And simpler, judging from the source!)
Just for the lols i visited the link on my phone... It worked! All the blurs and reflections all of it worked. Hats off to your team. Frame rates though were laggy but i'm still impressed.
I love WebGL and 3D graphics and particles, and love seeing WebGL becoming ubiquitous (when I first played with it I had to download a nightly of Firefox). But it's really hard to come up with a business use case that justifies using WebGL in say, a marketing product, or an online marketplace.
That is so cool. There's a great demo of orbitals and the like that can be picked up from this. I would have loved if a physics teacher showed me something like this when I was in school.
I made a test a while back to see how Canvas performs with particles : http://codepen.io/sakri/full/ntLAv . If I select the "per pixel" method, on my old laptop I get 60fps with 80,000 particles. I wasn't very impressed :D (although I'm sure the code could be improved)
This is always the first thing I do with one of these. It's so satisfying. On this one, if you make big, fast circles so the blob is moving as little as possible, then you let go, you can get the whole blob to just drift off to the side and stop (it disappears), so when you mousedown again somewhere else, you get a big stream of them all coming from the same general area.
I've looked over the code and I can't figure out what makes the particles brighter. Some of it is when the particles overlap, they appear brighter, but if you don't touch the screen, all the particles fade out to black. Anyone know how that is done?
The particles are drawn as line segments, with lengths proportional to their velocity. As the velocity approaches zero, each line segment covers a smaller and smaller fraction of a pixel. Because the lines are drawn with antialiasing (at least in Chrome) this causes them to fade into transparency as the pixel coverage approaches zero.
It basically means that the particle color is added on top of the already rendered particles (with the alpha value used to modulate the particle color, which is a bit strange, it would be more usual to use gl.ONE for both parameters). The more particles overlap, the brighter that pixels becomes.
Plus what teraflop writes about particle velocity being proportional to their line length. The 'overbrightening effect' should be caused by the blending however.
Since these particles aren't dynamic, they are much easier to render at high volume. You create the vertex buffers once and you're done. Dynamic particles are a lot more complicated, since the buffer needs to be updated constantly.
If anyone has some good articles about how to render a large number of dynamic particles, where the simulation happens on the CPU (i.e. it's not all shader trickery), using modernish OpenGL (no fixed function stuff), please share. I'm eager to learn more about it, but haven't found good resources. It's a blocking issue towards my goal of creating a bullet hell shoot-em-up game.
Unfortunately dynamic buffer updates is one of the tricky parts to do right in OpenGL since you need to assume what the driver does under the hood, and the best technique depends on what GL version you're targeting, and what GL extensions are available.
The developer could improve this page by adding a demo mode that shows the particles moving randomly around the screen. The demo mode could be shown after a couple seconds of user inactivity.
The particles are attracted by the position of the mouse, each having a slightly different (randomized) attraction factor.
If a particle ever reaches the exact mouse coordinates, its position is randomly generated anywhere on the screen.
When rendering the particles, it simply draws a line between the previous and the new position. So when a particle is transported to a random place, it create the rays that appear around the cursor.
There's no real complexity in the maths involved, but I remember spending quite some time tweaking the random ranges to get something nice.
Have you seen this VR demo: http://youtu.be/fAhzW4blqvM ? It looks similar enough that I bet it's inspired by yours.
Yours is a very fun demo. I tried modifying it to move more work to the GPU. I had the CPU only update a subset of the particles each frame and the GPU would interpolate a curve to fill in the missing frame updates. It sorta worked. It was N-times faster and could do more particles. But, the interpolated curves were progressively less responsive and fun.
http://www.iamnop.com/particles/