A poor man’s particle system

For a recent Flash job, I was required to add a particle system on top of an application already very CPU heavy. The project involved a large stage size, AR marker detection from a webcam feed, and a 3D-orientated plane displaying a running video, attached to the marker. This video plane then had to spew out various flavours of 3D particle at appropriate moments in the FLV.

The idea of plugging in a sexy particle engine like Flint, when the SWF was struggling even to maintain its target framerate of 25fps, made me uncomfortable. Bespoke seemed the only way to go, and hey! it worked out. Here’s what one of the particle types ended up resembling:

(It’s worth mentioning that fewer particles than can be made in the above demo were needed for the project itself. Maxing out the version here gets my CPU usage up to around 40%, which would not have left enough room for the marker tracking and FLV playback.)

To briefly cover the tricks used here, I faked 3D z-positioning by scaling clips as a function of their bespoke ‘zPosition’ value. The formula: focalLength / (focalLength + zPosition) gives the scale factor used to set the scaleX and scaleY properties of each MovieClip. The scaleX parameter was also adjusted to spoof motion blur, by overriding the x position property, and repeatedly comparing it to its value at the last update. The greater the change, the larger the scaleX multiplier, and the more stretched/blurred the particle would appear.

Rotation of the whole particle field was done by avoiding setting the x or z properties directly, depending instead on ‘radius’ and ‘rotational offset’ values. All the particles reside inside an imagined cylinder (the particle field), with its central spindle aligned with the y-axis. Each particle has its x and z location calculated on the basis of this rotation and distance from the central axis, as they move in their orbits. Channelling Mr McCallum, my secondary school maths teacher, the formulae to do this kind of positioning are, for the x axis: cos(angle) * radius; and for the z axis: sin(angle) * radius. (These can be used instead with the x and y properties to show rotation around a flat circle as opposed to the cylinder.)

In addition to rotary motion, the particles were required to ‘wander’ of their own accord. To achieve this, a large bitmap of Perlin noise is generated at the beginning of the simulation, with a reference to it passed to each particle instance. Going from pixel to pixel each frame, the RGB value is sampled and used to increment the y-velocity and radius-velocity of each particle. Over time, the Perlin noise is traversed completely, resulting in a wide range of even motion. Each particle begins sampling from a randomised row/column too, so that the movement is staggered.

Thanks Ken Perlin!
Setting the Perlin noise generation to tile allows the bitmap to be traversed from side to side and top to bottom without any sudden changes in value.

With all said and done, there may indeed have been a package out there that was equally lightweight and flexible enough for the nuances of the project. But, hard deadlines being as they are, it sometimes pays just to go from the ground up, omitting any chaff on the way – rather than hunt for elusive wheat through sprawling, multifaceted libraries.

If the source code happens to be of use to anyone I’d be very happy to clean it up and post it here. Until then… indolence wins out. Sorry!

Rain simulation

As a generative animation exercise (and also just because, um, rain is nice-?), I decided to code me up some good ol’ precipitation. Considerations included: degree of realism, adaptability and performance. Specifically, animating a single layer of tear-shaped drops falling uniformly in perfectly straight lines is relatively easy to do, and certainly has its place within the right art style. On the other hand, ultra-realism would entail thousands of varied and varying particles, deeply distributed in 3D space – something that would better suit pre-rendering than realtime animation, or at the very least, something other than Flash. But that would be no fun at all. I opted for a low-ish number of convincing enough, but inaccurately shaped, particles (apparently raindrops are actually round, mushroom-top blobs – who knew?!), with fairly realistic motion and three distinct layers for the parallactic goodness. I tried to keep everything as configurable as possible, so fall speed, wind strength, blustery-ness, particle graphic, drop size variation and viewport size can be adjusted easily. Reuse or lose! – as they say. Well, they ought to start saying that.
On with the rain!:

You may notice that in the front and backmost layers, the drops are a little blurred. I wanted to give a narrow depth of field effect, and had initially applied a BlurFilter to their containing sprites, but that hit performance hard – so I drew a separate drop symbol for their layers, softening the perimeter with a radial gradient down to transparent, which is just as cheap performance-wise as a solid drop.

Thinking a little more about the worth of such an effect, I realised that I would likely want the rain to interact with whatever other objects might be in the scene. And so I added an umbrella:

It didn’t make much sense for the umbrella to stop drops across all layers, but the effect wasn’t very noticeable with so many other drops falling past it, so I removed them for this demo. I also added some physics-y hinged swinging based on the umbrella’s sideways movement. A splash animation plays at the exact intersecting point of drop and canopy – but I only later realised that, since around 75 drops make contact every second, I could easily have randomised the locations of the splashes and simplified the collision detection. Still! – honesty is the best policy, and when it’s only drizzling, accuracy of the contact point is more relevant.

So now I have almost everything I need for my ‘KEEP THE LOST KITTIES DRY’ minigame. No need to thank me just yet, world.

I drew the visual assets in the Flash CS3 IDE, compiled my classes in the wonderfully lightweight FlashDevelop, and animated the drops using Tweener. That’s all!


I'm Adam Vernon: front-end developer, free-time photographer, small-hours musician and general-purpose humanoid.