/* * Blowing Hair effect * P.Leskinen 12 January MMIX * Hairy Text Blowing in a Perlin Wind */ package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BitmapDataChannel; import flash.display.BlendMode; import flash.display.Sprite; import flash.events.Event; import flash.filters.BlurFilter; import flash.filters.ConvolutionFilter; import flash.filters.DisplacementMapFilter; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; import flash.text.*; public class BlowingInTheHair extends Sprite { public var source:*; public var margin:int = 40; // white space around // controls the hair length public var hairLength:Number = 8.0; // density: // 0.0 = solid // 0.99 = just a few hair public var density:Number = 0.85; public var contrast:Number = 1.5; protected var bmd:BitmapData; protected var perlinMap:BitmapData; protected var canvas:BitmapData; protected var offsets:Array; internal var i:int, j:int; internal const NEWMATRIX:Matrix= new Matrix(); internal const NEWPOINT:Point= new Point(); internal const NEWCOLORTRANSFORM:ColorTransform = new ColorTransform(); internal const BLUR:BlurFilter = new BlurFilter(2,2); // or try (1,8); public function BlowingInTheHair () { // create a text element with( source= new TextField() ) { defaultTextFormat= new TextFormat( "Arial", 70, 0x654321 ); htmlText="Hello world"; multiline = true; width= 360.0; } initStage(); } // init bitmapdatas and listeners: private function initStage():void { var w:int, h:int; bmd= new BitmapData( w= source.width+2*margin, h= source.height+2*margin, true, 0x00); perlinMap = new BitmapData(w,h, false); offsets= [new Point(), new Point(), new Point()]; canvas = new BitmapData(w,h, true,0x00); addChild(new Bitmap(canvas)); addEventListener(Event.ENTER_FRAME, generate); } private function generate(e:Event =null):void { // creating the 'blowing' offsets[0].x -= 8.0; offsets[1].x += 5.2; offsets[2].x += 2.8; offsets[0].y += 2.0; offsets[1].y -= 1.6; offsets[2].y -= 0.4; perlinMap.perlinNoise(perlinMap.width/2,perlinMap.height/2, 3,11,true,true, BitmapDataChannel.BLUE + BitmapDataChannel.GREEN, false, offsets); // creating the effect: var displacer:DisplacementMapFilter = new DisplacementMapFilter(perlinMap, NEWPOINT, BitmapDataChannel.BLUE,BitmapDataChannel.GREEN, hairLength,hairLength); canvas.lock(); canvas.fillRect(canvas.rect, 0x00); canvas.draw(source, new Matrix(1,0,0,1,margin,margin)); // pixelDissolve to set some pixels to completely transparent // , without this would be a 'solid mass' canvas.pixelDissolve(canvas, canvas.rect, NEWPOINT, 11, density*canvas.width*canvas.height, 0x000000); canvas.applyFilter(canvas, canvas.rect, NEWPOINT, BLUR); canvas.applyFilter(canvas, canvas.rect, NEWPOINT, new ConvolutionFilter(3,3,[0, 1, 1.5, -1, contrast, 1, -1.5, -1, 0],contrast, 0, true) ); // repeat a serie of displacements to achieve a hair effect // number of iterations, bigger value for smoother hair, but slows down for (i=0; i!=5; i++) { displacer.scaleX = displacer.scaleY *= 1.4; bmd.applyFilter(canvas, bmd.rect, NEWPOINT, displacer); canvas.draw(bmd,NEWMATRIX , // modify to change the color: new ColorTransform(1.22,1.2,0.95,1.0), BlendMode.LIGHTEN); } canvas.unlock(); } } } BlowingInTheHair