A while back I was given my first flash project that required me to use Papervision 3D. If that wasn’t daunting enough, the design of the project required that there be a depth of field effect on the elements – something that papervision cannot do. (If i am wrong about that, please don’t tell me now…)
After learning the basics of papervision – which has plenty of tutorials on the interwebs – I started brainstorming an approach for faking depth of field. Here is what I came up with.
Simplifying the concept, I basically just needed to ‘blur’ the objects as they moved close to or far away from the camera. I couldn’t blur the object itself, but I could change the textures on the fly, so that became the basis of my approach.
I couldn’t just blur the textures on the objects because the edges would not look right. The blur needed to extend past the edge of the objects. My solution for this was to set up extra 3d planes for each of the objects that needed blur. As the objects moved, their distance from the camera was tested. If they were outside the threshold area, the blurred plane object was substituted in, and the blurry textures were swapped around based on the particular distance.
It seemed to work pretty well. Here is a slightly simplified version of the concept, using just the planes. As you move the mouse around, you will see the planes appear to blur – this is the textures swapping
Now for the funky bit. Because there were a bunch of different textures I needed to work with, I didn’t want to have to created every level of blur for every image. It would be burden on my time and increase download times.
What I ended up doing was created a method that took in one texture and generated all of the blurs for me. Each of the different blurs was then stored in an array so that I could easily switch between them.
This is the code that I used, but looking at it now I could have done it a bit better dropping out the ‘draw()’ method and applying the blur to the BitmapData directly.
/** * Generates an array of bitmap data objects ranging from no blur to the blur amount * @param origBitmapData - the original bitmap to blur * @param blurAmount - the maximum amount of blur to create * @param steps - the number of various blur amounts to generate * @return An array of BitmapData objects */ public function generateBlurredBitmapArray(origBitmapData:BitmapData, blurAmount:Number = 40, steps:Number=8):Array { // set up a return array to hold the data var returnArray:Array = []; // create the blur filter var blur:BlurFilter = new BlurFilter(0,0,2); // generate a sprite to apply the blur to var s:Sprite = new Sprite(); // create a bitmap to hold the original bitmap data - add it to the sprite var b:Bitmap = new Bitmap(origBitmapData, "auto", true); s.addChild(b); // position it in the centre b.x = b.y = blurAmount; // loop through and generate the required number of blurs for (var i:uint = 0; i < steps; i++) { // adjust the blur and apply it to the sprite blur.blurX = blur.blurY = blurAmount * (i / (steps - 1)) s.filters = [blur]; // generate the new bitmap data var newBmpData:BitmapData = new BitmapData(origBitmapData.width + (blurAmount * 2), origBitmapData.height + (blurAmount * 2), true, 0x00ffffff); // draw the sprite to it newBmpData.draw(s, null, null, null, null, true); // add this to the return array returnArray.push(newBmpData); } // return the array return returnArray; }
That’s about it. Hope that helps you out – let me know what you think!