2012-05-05 33 views

回答

2

Pixel Bender ist krieg!

儘管我同意以前的答案,但我想指出的是,您可以通過僅使用多年的位圖過濾器來實現這種效果:DisplacementMapFilter即。創建一個位移貼圖,以圓形方向移動像素,並多次將此貼圖應用於圖像。這會讓你變成一個漩渦。

這是我的簡單實現。
用法非常簡單(參見課後)。

package org.noregret.images 
{ 
    import flash.display.BitmapData; 
    import flash.display.BitmapDataChannel; 
    import flash.display.BlendMode; 
    import flash.display.DisplayObject; 
    import flash.display.GradientType; 
    import flash.display.InterpolationMethod; 
    import flash.display.SpreadMethod; 
    import flash.display.Sprite; 
    import flash.filters.DisplacementMapFilter; 
    import flash.filters.DisplacementMapFilterMode; 
    import flash.geom.Matrix; 
    import flash.geom.Point; 
    import flash.geom.Rectangle; 

    /** 
    * @author Nox Noctis (http://noregret.org) 
    */ 
    public class Swirl 
    { 
     public var target : DisplayObject; 
     public var allowCache : Boolean = false; 
     public var levels : uint; 
     public var isDestroyed : Boolean; 

     protected var bitmapMargin : Point; 
     protected var filter : DisplacementMapFilter; 
     protected var radius : int; 
     protected var cache : Object; 
     protected var map : BitmapData; 

     protected var targetRect : Rectangle; 
     protected var mapOffset : Point; 
     protected var maxLevel : Number = 1; 

     public function Swirl(_target : DisplayObject, _filterLevels : uint = 10, _allowCache : Boolean = true) 
     { 

      target = _target; 
      allowCache = _allowCache; 
      levels = _filterLevels; 

      cache = {}; 

      filter = new DisplacementMapFilter(); 
      filter.componentX = BitmapDataChannel.RED; 
      filter.componentY = BitmapDataChannel.GREEN; 
      filter.scaleX = -20; 
      filter.scaleY = -20; 
      filter.mapPoint = new Point(); 
      filter.mode = DisplacementMapFilterMode.IGNORE; 
     } 

     private function createDisplacementMap() : void 
     { 
      targetRect = target.getRect(target); 

      radius = Math.max(Math.max(targetRect.width, targetRect.height), 100)/2; 
      radius = Math.sqrt(2) * radius; 

      mapOffset = new Point(radius - targetRect.width/2, radius - targetRect.height/2); 

      var mapSprite : Sprite = new Sprite(); 
      var redLayer : Sprite = new Sprite(); 
      var greenLayer : Sprite = new Sprite(); 
      var grayLayer : Sprite = new Sprite(); 
      mapSprite.addChild(redLayer); 
      mapSprite.addChild(greenLayer); 
      mapSprite.addChild(grayLayer); 

      var gradientMatrix : Matrix; 

      gradientMatrix = new Matrix(); 
      gradientMatrix.createGradientBox(radius * 2, radius * 2, Math.PI/2, -radius, -radius); 

      redLayer.graphics.lineStyle(0, 0, 0); 
      redLayer.graphics.beginGradientFill(GradientType.LINEAR, [0xFF0000, 0], [100, 100], [0, 255], gradientMatrix, SpreadMethod.PAD, InterpolationMethod.RGB); 

      redLayer.graphics.drawCircle(0, 0, radius); 
      redLayer.graphics.endFill(); 


      greenLayer.graphics.lineStyle(0, 0, 0); 
      gradientMatrix.createGradientBox(radius * 2, radius * 2, 0, -radius, -radius); 
      greenLayer.graphics.beginGradientFill(GradientType.LINEAR, [0x00FF00, 0x00FF00], [0, 100], [10, 245], gradientMatrix, SpreadMethod.PAD, InterpolationMethod.RGB); 

      greenLayer.graphics.drawCircle(0, 0, radius); 
      greenLayer.graphics.endFill(); 
      greenLayer.blendMode = BlendMode.ADD; 


      gradientMatrix = new Matrix(); 
      gradientMatrix.createGradientBox(radius * 2, radius * 2, 0, -radius, -radius); 
      grayLayer.graphics.lineStyle(0, 0, 0); 
      grayLayer.graphics.beginGradientFill(GradientType.RADIAL, [0x808080, 0x808080], [0, 100], [0, 0xFF], gradientMatrix, SpreadMethod.PAD, InterpolationMethod.RGB); 
      grayLayer.graphics.drawCircle(0, 0, radius); 
      grayLayer.graphics.endFill(); 

      var rect : Rectangle = mapSprite.getRect(mapSprite); 
      var matrix : Matrix = new Matrix(); 
      matrix.translate(-rect.x, -rect.y); 
      if (map) { 
       map.dispose(); 
      } 
      map = new BitmapData(rect.width, rect.height, false, 0xFF808080); 
      map.draw(mapSprite, matrix); 
      filter.mapBitmap = map; 
     } 

     public function swirlTo(ratio : Number) : BitmapData 
     { 
      if (isDestroyed) { 
       trace("Swirl: error! Tried to swirl on disposed item."); 
       return null; 
      } 
      if (ratio < 0) { 
       ratio = 0; 
      } 

      var level : uint = Math.round(levels * ratio); 
      var cacheName : String = getCacheName(level); 
      if (cache[cacheName]) { 
       return (cache[cacheName] as BitmapData).clone(); 
      } 

      var rect : Rectangle = target.getRect(target); 
      if (!map || rect.width != targetRect.width || rect.height != targetRect.height) { 
       createDisplacementMap(); 
       flushCache(); 
      } 

      var point : Point = new Point(-targetRect.x, -targetRect.y); 
      bitmapMargin = new Point(point.x + mapOffset.x, point.y + mapOffset.y); 

      var bmp : BitmapData; 
      if (cache["l" + maxLevel]) { 
       bmp = cache["l" + maxLevel] as BitmapData; 
      } else { 
       bmp = new BitmapData(map.width, map.height, true, 0); 
       var matrix : Matrix = new Matrix(); 
       matrix.translate(bitmapMargin.x, bitmapMargin.y); 
       bmp.draw(target, matrix, null, null, null, true); 
      }    

      if (level == 0) { 
       cache[cacheName] = bmp.clone(); 
       return bmp; 
      } 

      var destPoint : Point = new Point(); 
      for (var i : Number = maxLevel;i <= level; i++) { 
       bmp.applyFilter(bmp, bmp.rect, destPoint, filter); 
       if (allowCache) { 
        cache["l" + i] = bmp.clone(); 
       } 
      } 
      maxLevel = Math.max(maxLevel, level); 

      return bmp; 
     } 

     private function getCacheName(level : uint) : String 
     { 
      return "l" + level; 
     } 

     public function flushCache() : void 
     { 
      for each (var bmp:BitmapData in cache) { 
       bmp.dispose(); 
      } 
      cache = {}; 
     } 

     public function destroy() : void 
     { 
      flushCache(); 
      target = null; 
      map.dispose(); 
      map = null; 
      isDestroyed = true; 
     } 
    } 
} 

用例:

package 
{ 
    import flash.display.Sprite; 
    import flash.display.Loader; 
    import flash.events.Event; 
    import flash.net.URLRequest; 
    import flash.system.LoaderContext; 
    import flash.display.Bitmap; 
    import org.noregret.images.Swirl; 

    [SWF(width="800",height="600",backgroundColor="#FFFFFF",fps="30")] 
    public class TestSwirl extends Sprite 
    { 
     private const loader:Loader = new Loader(); 
     private const swirlBitmap:Bitmap = new Bitmap(); 
     private var swirl:Swirl; 
     private var time:Number = 0; 

     public function TestSwirl() 
     { 
      loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete); 
      var request:URLRequest = new URLRequest("http://i.stack.imgur.com/Vtsvm.gif"); 
      loader.load(request, new LoaderContext(true));    
     } 

     protected function onLoadComplete(event:Event):void 
     { 
      var original:Bitmap = loader.content as Bitmap; 
      addChild(original); 

      swirlBitmap.bitmapData = original.bitmapData.clone(); 
      swirlBitmap.x = original.x + original.width + 10; 
      addChild(swirlBitmap);   

      swirl = new Swirl(original,80); 
      addEventListener(Event.ENTER_FRAME, onEnterFrame); 
     } 

     protected function onEnterFrame(event:Event):void 
     { 
      var ratio:Number = Math.abs(Math.sin(time)); 
      // *** 
      swirlBitmap.bitmapData = swirl.swirlTo(ratio); 
      // *** 
      time += .02; 
     } 
    } 
}