1

我想对一些 BitmapData 进行操作和动画处理以创建漩涡效果,例如在下面的链接中找到的效果:

http://www.flash-filter.net/swirl-effect.phtml

我可以应用哪些技术?

顺便说一句:是的,我知道效果很丑......

4

4 回答 4

3

如果您正在寻找如何实现漩涡效果,即算法。以下是关于如何转换图像的一个很好的分步说明:Image- Twist and Swirl Algorithm

于 2012-05-05T16:19:02.203 回答
2

像素折弯机是克里格!

虽然我同意前面的答案,但我想指出,您可以通过仅使用多年来存在的位图过滤器来实现这种效果:即 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;
        }
    }
}
于 2012-05-05T19:58:13.637 回答
2

为此有一个Pixel Bender过滤器。看看这个链接:

http://www.adobe.com/cfusion/exchange/index.cfm?event=extensionDetail&extid=1536021

这是关于补间 Pixel Bender 滤镜的教程

http://plasticsturgeon.com/2011/03/pixel-transition-tweening-a-pixel-bender-filter-in-as3/

您可能还想查看 AS3 ImageProcessing 库

http://blog.joa-ebert.com/imageprocessing-library/

这应该给你一个很好的起点

于 2012-05-05T15:08:51.390 回答
1

我建议使用Pixel Bender创建您自己的位图滤镜。

于 2012-05-05T15:08:33.933 回答