Faster Metaballs in AS3 with Pixel Bender



I’ve always loved watching meta balls. There’s nothing to dislike about digital goo… except maybe that it’s fairly processor intensive, and that AS3 doesn’t do processor intensive too well. That’s where native functions and Pixel Bender come into play.
Come see my goo!

Flash Content

Flash loading… or you don’t have flash. Your call.


Click here if you have flash blocked

Shift + F6-F8 to fiddle with options

By using a few native function calls, and letting Pixel Bender handle others in its own wee thread, it’s fairly easy to implement without the marching squares algorithm, and filters aside, boils down to about 10 lines of code.

First, apply a nice hearty gaussian blur to the blobs. A radius of 8 – 10 px does pretty well in this case. Instead of using an 8 pixel neighbour sample, and layering it, it’s best just to use the native GlowFilter here as that offers fantastic resolution at very high speeds.

As the blobs get closer to eachother, the blurry overlap will become more opaque, so next apply a threshhold filter.
Cut out areas with an alpha less than about 0.9 (0xFA), and the areas between two nearby blobs will begin to join. I used about 2 lines of pixel bender for this one.

Pros and cons? It doesn’t behave exactly like regular implementations, but it’s fast as all hell – fast enough for example to be used in water simulation and like the original code, two blobs sharing the same space will make a slightly larger blob.


Pixel Bender Threshold:


  1.     void evaluatePixel()
  2.     {
  3.         dst = sampleNearest(src,outCoord());
  4.         if ( dst.> pie ){ dst.rgba = defaultColor; }
  5.     else {dst.rgba = pixel4(0.0,0.0,0.0,0.0);}
  8.     }

AS3 Code


  1.         public var fRect:Rectangle = new Rectangle(0, 0, GAMEWIDTH, GAMEHEIGHT);
  2.         public var zZ:Point = new Point(0, 0);
  3.         public var glowFilter:GlowFilter = new GlowFilter(0x223344, 1, 20, 20, 2);
  4.         public var bevelFilter:BevelFilter = new BevelFilter(16, 45, 0x667788, 0.5, 0x223344, 0.5, 12, 12);
  6.         private function onFrame(e:Event = null) {
  8.             testBitmap.bitmapData.fillRect( fRect, 0x00000000);
  9.             updateBlobs();
  11.             testBitmap.bitmapData.applyFilter( testBitmap.bitmapData, fRect,zZ, glowFilter );
  13.             testBitmap.bitmapData.applyFilter( testBitmap.bitmapData, fRect,zZ,  threshFilter);            
  15.             testBitmap.bitmapData.applyFilter( testBitmap.bitmapData, fRect,zZ, bevelFilter );
  17.             fpsCounter.update();
  19.         }


 Alternatively, the threshhold filter can be applied with the native bitmapData threshhold:

  1. fluidData.threshold( fluidData, new Rectangle(0, 0, fluidData.width, fluidData.height), 
  2.  new Point(0, 0), “>=”,  0x88000000, 0xFF0000BB, 0xFFFFFFFF, false );


 By using the same bitmapData as the source and destination, the function won’t cut out the blurry bits – but instead draw the solid color on top. Simple solution: bitmap2.threshhold(bitmap1);

To learn a little more, or play with some 3D meta balls, have a look at this link which describes using Pixel Bender to perform the calculations as opposed to producing the image.



Leave a Reply

Your email address will not be published. Required fields are marked *