DirectionalBlurFilter && .swc Library and Stuff

Since the release of Flash 10, I’ve seen a few blog posts about creating .swc libraries that can be used in Flash. Probably the most in depth was Mike Chambers article “Creating Re-distributable Actionscript Libraries of Pixel Bender Filters”. Needless to say, I had to give it a go, myself. So, I fired up Pixel Bender and created the DirectionalBlurFilter seen below.

//  Directional Blur
//  01NOV08
//  
//  TODO:
//  Blur from image center - not image origin

kernel DirectionalBlur
<   namespace :     "com.onebyonedesign";
    vendor :        "Devon O. Wolfgang";
    version :       1;
    description :   "Directional Blur";
>
{
    parameter float angle
    <
        minValue:       0.0;
        maxValue:       360.0;
        defaultValue:   0.0;
    >;
    
    parameter float blurAmount
    <
        minValue:       0.0;
        maxValue:       1.0;
        defaultValue:   0.0;
    >;
    
    input image4 src;
    output pixel4 dst;

    void
    evaluatePixel()
    {
        float2 offset;
        float rads = radians(angle);
        
        offset.y = sin(rads);
        offset.x = cos(rads);
        
        //  add a little more blur
        float amount = blurAmount * 5.0;
        
        offset *= amount;
        
        //  number of sampled images
        int count = 30;
        
        //  very annoying pseudo loop
        dst += sampleNearest( src, outCoord() + offset * float(0) );
        dst += sampleNearest( src, outCoord() + offset * float(1) );
        dst += sampleNearest( src, outCoord() + offset * float(2) );
        dst += sampleNearest( src, outCoord() + offset * float(3) );
        dst += sampleNearest( src, outCoord() + offset * float(4) );
        dst += sampleNearest( src, outCoord() + offset * float(5) );
        dst += sampleNearest( src, outCoord() + offset * float(6) );
        dst += sampleNearest( src, outCoord() + offset * float(7) );
        dst += sampleNearest( src, outCoord() + offset * float(8) );
        dst += sampleNearest( src, outCoord() + offset * float(9) );
        dst += sampleNearest( src, outCoord() + offset * float(10) );
        dst += sampleNearest( src, outCoord() + offset * float(11) );
        dst += sampleNearest( src, outCoord() + offset * float(12) );
        dst += sampleNearest( src, outCoord() + offset * float(13) );
        dst += sampleNearest( src, outCoord() + offset * float(14) );
        dst += sampleNearest( src, outCoord() + offset * float(15) );
        dst += sampleNearest( src, outCoord() + offset * float(16) );
        dst += sampleNearest( src, outCoord() + offset * float(17) );
        dst += sampleNearest( src, outCoord() + offset * float(18) );
        dst += sampleNearest( src, outCoord() + offset * float(19) );
        dst += sampleNearest( src, outCoord() + offset * float(20) );
        dst += sampleNearest( src, outCoord() + offset * float(21) );
        dst += sampleNearest( src, outCoord() + offset * float(22) );
        dst += sampleNearest( src, outCoord() + offset * float(23) );
        dst += sampleNearest( src, outCoord() + offset * float(24) );
        dst += sampleNearest( src, outCoord() + offset * float(25) );
        dst += sampleNearest( src, outCoord() + offset * float(26) );
        dst += sampleNearest( src, outCoord() + offset * float(27) );
        dst += sampleNearest( src, outCoord() + offset * float(28) );
        dst += sampleNearest( src, outCoord() + offset * float(29) );
        
        //  no loops allowed
        /*
        for (int i = 0; i < count; i++) {
            dst += sampleNearest( src, outCoord() + offset * float(i) );
        }
        */
        
        //  normalize image
        dst /= float(count);
    }
}

What I dislike most about it is that the object blurs from the edge rather than the center, cutting the blur off rather abruptly. If anyone knows how to fix that or knows of a better Directional or Motion Blur filter, don't hesitate to post. Lord knows when it comes to Pixel Shader coding, I'll be the first to admit, I'm not exactly your "go to guy".

In any case, after creating the "peanut butter and jelly file" (that's a .pbj for those wondering), compiling it into a .swc (according to Mike Chambers' instructions) and compiling that .swc file within a Flash .swf I got the below example.

[kml_flashembed movie="http://blog.onebyonedesign.com/wp-content/uploads/2008/10/directonalblur.swf" height="400" width="400" /]

The actionscript was simple enough - and I love the ability to treat my own filters just like a native Flash filter (just wish I was better at writing them).

package {
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import caurina.transitions.Tweener;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import src.filters.DirectionalBlurFilter;
	
	/**
	 * ...
	 * @author Devon O.
	 */
	public class Main extends Sprite {
		
		//	Euro is item in .fla library
		private var _euro:Euro;
		private var _dirFilter:DirectionalBlurFilter;
		
		public function Main():void {
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);
			
			var instructions:TextField = new TextField;
			instructions.mouseEnabled = false;
			instructions.selectable = false;
			instructions.defaultTextFormat = new TextFormat("_sans", 12);
			instructions.autoSize = TextFieldAutoSize.LEFT;
			instructions.text = "Click around the stage.";
			instructions.y = 5;
			instructions.x = int(stage.stageWidth * .5 - instructions.width * .5);
			addChild(instructions);
			
			_dirFilter = new DirectionalBlurFilter();
			
			_euro = new Euro();
			_euro.x = 40;
			_euro.y = 40;
			addChild(_euro);
			
			stage.addEventListener(MouseEvent.CLICK, moveCoin);
		}
		
		private function moveCoin(event:MouseEvent):void {
			var tx:Number = event.stageX;
			var ty:Number = event.stageY;
			var rad:Number = Math.atan2(_euro.y - ty, _euro.x - tx);
			var angle:Number = rad * 180 / Math.PI;
			
			_dirFilter.angle = angle;
			_dirFilter.blurAmount = 1;
			
			var dataObj:Object = { blurAmount:1 };
			
			Tweener.addTween(_euro, { x:tx, y:ty, time:.5, transition:"easeOutQuad" } );
			Tweener.addTween(dataObj, { blurAmount:0, time:.5, transition:"easeOutQuad", onUpdate:applyBlur, onUpdateParams:[dataObj] } );
		}
		
		private function applyBlur(o:Object):void {
			_dirFilter.blurAmount = o.blurAmount;
			_euro.filters = [_dirFilter];
		}
	}
}

In other news, yes it's been awhile, but I've been extremely busy lately with the new job and just settling into a new country in general. The company I'm working for now, just picked up an IIA NetVisionary award the other day and is now shortlisted for two Golden Spider awards. Wish I could say I helped out, but the awards are for projects created before my arrival. Still, it's a great atmosphere to be coming into.

Ireland is a wonderful country - the people here have been terrific about welcoming this foreigner into their midst. And, of course, finally living together with my wife for the first time in nearly 3 years of marriage is the best thing ever. Who knew life could be so good?

Date: