FLASH AS3 滤镜(Filter)

原文地址:http://bbs.9c9t.com/thread-196141-1-1.html

FLASH AS3 滤镜(Filter)

  滤镜(Filter)
          滤镜是一些位图的效果,可以应用于任何显示对象。在 Flash IDE 中可以通过滤镜面
          板或使用时间轴的 ActionScript 来使用滤镜,由于这本书是关于 ActionScript 的,所以
          只能简朴地讨论一下应用滤镜的方法。在 AS 3 中包括以下几种滤镜:
          ■ Drop shadow(投影滤镜)
          ■ Blur(模糊滤镜)
          ■ Glow(发光滤镜)
          ■ Bevel(斜角滤镜)
          ■ Gradient bevel(渐变斜角滤镜)
          ■ Gradient glow(渐变发光滤镜)
          ■ Color matrix(颜色矩阵滤镜)
          ■ Convolution(卷积滤镜)
          Displacement map(置换图滤镜)
          虽然不能一一介绍每种滤镜的使用细节,但大家可以通过帮助文档来学习。在书中还会
          有很多滤镜使用的例子,所以在这里只介绍一下滤镜使用的总体方法和两个具体实例。
          创建滤镜
          通过使用 new 关键字及滤镜名来创建滤镜,并给出所需的参数。例如,创建一个 blur
          filter(模糊滤镜),最简朴的一种滤镜,写法入下:
          var blur:BlurFilter = new BlurFilter(5, 5, 3);
          参数分别为 blurX,blurY,quality。这个例子会将对象在 x和 y 轴上模糊 5 个像素,模糊
          的品质为中等。
          另一点需要知道的是滤镜在其名为 flash.filters 的包中。所以要在文件的开始处将它们
          导入进来:
          import flash.filters.BlurFilter;
          如果希望导入包中所有的滤镜,可以使用简写:
          import flash.filters.*;   69
          现在,我们可以直接创建任何类型的滤镜了,但是一般来说,除非要使用这个包中的大
          部分滤镜,否则最好避免使用通配符(*),而是明确地导入所需要的类。这样做只是为了能
          够清楚,哪些是真正想要导入的而哪些不是。好了,现在已经创建了一个模糊滤镜,但怎样
          才能使它去模糊一个对象呢?
          任何一个显示对象都有一个名为 filters 的属性,这是一个包括了所有滤镜的数组,
          因为如果一个对象要应用多个滤镜,那么只需要再将模糊滤镜放到数组中即可。乐观地看,
          应用滤镜应该可以像使用基本数组操作那样简朴,push,就像这样
          mySprite.filters.push(blur);,但是很遗憾,没有这么简朴。在整个数组赋值为 filters
          之前,Flash 不关心 filters 数组的变化。
          如果已知对象没有应用任何的滤镜,或想要重写它们,只需要孝蕤一个数组,将我们的
          滤镜粘在上面,再将这个新数组赋给 filters 属性就可以了。先来试一下,下面一个文档
          类 Filters.as,创建了一个 sprite 影片并且在里面绘制了一个黄色的正方形,然后,创
          建一个滤镜,加入数组中,最后将数组赋给 sprite 的 filters 属性:
          package {
          import flash.display.Sprite;
          import flash.filters.BlurFilter;
          public class Filters extends Sprite {
          public function Filters() {
          init();
          }
          private function init():void {
          var sprite:Sprite = new Sprite();
          sprite.graphics.lineStyle(2);
          sprite.graphics.beginFill(0xffff00);
          sprite.graphics.drawRect(100, 100, 100, 100);
          sprite.graphics.endFill();
          addChild(sprite);
          var blur:BlurFilter = new BlurFilter(5, 5, 3);
          var filters:Array = new Array();
          filters.push(blur);
          sprite.filters = filters;
          }
          }
          }
          瞧!出现了一个模糊的黄色方块儿。重要的部分用黑体着重,我们可以简写一点:
          var blur:BlurFilter = new BlurFilter(5, 5, 3);
          var filters:Array = [blur];
          sprite.filters = filters;
          或再短一点:
          sprite.filters = [new BlurFilter(5, 5, 3)];
          在创建数组的同时,将滤镜放进去,并应用 filters 属性,这样一来,Flash 会很高
          兴。
          但是如果已经有了滤镜并希望继续使用,这时,但又不确定是否有滤镜存在,那该怎样
          办呢?在 Flash 8 中,这是件很麻烦的事,因为一个显示对象的 filters 属性如果没有应
          用滤镜,那么它将是未定义(undefined)的。但在 AS 3 中, filters 数组总是保持为一个
          空数组,只需要给数组赋值,将滤镜 push 进去,并将其赋给对象的 filters 属性即可,
          方法如下:
          var filters:Array = sprite.filters;
          filters.push(new BlurFilter(5, 5, 3));   70
          sprite.filters = filters;
          如果使用这种方法,那么无论是否有滤镜存在都没有问题,滤镜只是被加入到数组列表
          中而已。因为 filters 属性是一套成熟的数组,所以可以使用不同的数组操作方法。比如,
          使用 concat 方法:
          sprite.filters = sprite.filters.concat(new BlurFilter(5, 5, 3));
          我不认为这是个“正娶诒的做法,大家只要知道将一个包涵有滤镜的数组赋给 filters
          属性就足够了。
          动态滤镜
          现在我们已经基本上知道了如何在 ActionScript 中使用滤镜了。接下来,用已经学过的知
          识,制作一个动态滤镜。这个效果,使用文档类 AnimatedFilters.as:
          package {
          import flash.display.Sprite;
          import flash.events.Event;
          import flash.filters.DropShadowFilter;
          public class AnimatedFilters extends Sprite {
          private var filterropShadowFilter;
          private var sprite:Sprite;
          public function AnimatedFilters() {
          init();
          }
          private function init():void {
          sprite = new Sprite();
          sprite.graphics.lineStyle(2);
          sprite.graphics.beginFill(0xffff00);
          sprite.graphics.drawRect(-50, -50, 100, 100);
          sprite.graphics.endFill();
          sprite.x = 200;
          sprite.y = 200;
          addChild(sprite);
          filter = new DropShadowFilter(0, 0, 0, 1, 20, 20, .3);
          addEventListener(Event.ENTER_FRAME, onEnterFrame);
          }
          private function onEnterFrame(event:Event):void {
          var dx:Number = mouseX - sprite.x;
          var dy:Number = mouseY - sprite.y;
          filter.distance = -Math.sqrt(dx * dx + dy * dy) / 10;
          filter.angle = Math.atan2(dy, dx) * 180 / Math.PI;
          sprite.filters = [filter];
          }
          }
          }
          首先在 sprite 中画一个正方形,正方形在 sprite 的居中位置,然后将 sprite 移动
          到舞台中间,用一些默认属性创建投影滤镜(DropShadowFilter)。
          添加一个 enterFrame 事件的侦听器及处理函数: onEnterFrame 方法, 用于计算角度(angle)
          及使用三角函数计算 sprite 影片与鼠标的距离(distance)。使用 angle 和 distance 设
          置投影滤镜的 angle 和 distance 属性,最后将这个滤镜再应用到 sprite 上。请注意, 71
          我们不需要每次都创建一个新的滤镜,可以继续使用同一个滤镜,只需要改变它的属性即可。
          然而,只是改变这些属性也不能更新 sprite 影片的显示。因此,还需要再将变化过的滤镜
          效果赋值给 filters 属性。
          位图(Bitmaps)
          与滤镜相同,可以用整本书来介绍 Bitmap 和 BitmapData 类,看起来也不错,但是这并不
          是本书的目的。我们将通过一些简朴的例子,用来指出 AS 2 与 AS 3 中位图处理的变化。
          在 AS 2 中,通过调用 BitmapData()函数,孝蕤一个 BitmapData 对象使用如下参数:
          new BitmapData (width:Number,
          height:Number,
          transparent:Boolean,
          fillColor:Number)
          你也许猜到了, BitmapData 类同样也是嵌入在一个包中,完整的使用名称如下
          flash.display.BitmapData。所以需要导入包,对于 width 和 height 参数则非常显而易
          见, transparent 参数表示创建的图像是否包涵一个 alpha 通道选择 true 或 false ,
          fillColor 是创建图像的初始颜色, 如果 transparent 为 true 的话, 那么位图就用 32 位
          色表示,0xAARRGGBB,如果为 false 的话,就可以使用 24 位安全色表示。
          在创建 BitmapData 对象时,也许很想能看到它的样子。在 AS 2 中,使用
          attachBitmap 命令在影片剪辑中添加一个位图。大家也许会想,现在是否可以使用
          addChild 在显示对象中添加一个位图,但事实上并没有这么简朴。问题在于 addChild 只
          对继承自 DisplayObject 类的对象起作用,如 Sprite 影片,影片剪辑和文本框。然而,
          如果我们研究一下类的结构,就会发现 BitmapData ,没有继承自 DisplayObject,所有不
          能直接添加对象。这就是为什么要有 Bitmap 类的原因, Bitmap 类几乎始终都有一个函数
          作为 BitmapData 实例的容器,可以这样创建:
          var myBitmapData:BitmapData = new BitmapData(100, 100, false, 0xff0000);
          var myBitmap:Bitmap = new Bitmap(myBitmapData);
          现在就可以将对象加入到显示列表了:
          addChild(myBitmap);
          使其可见后,Bitmap 实例也可以改变位置,进行缩放,增加滤镜等等。
          测试这个例子,只需要在第二章给出的类框架的 init 方法加入这三行就可以了,不要
          忘记导入 flash.display.Bitmap 和 flash.display.BitmapData,运行后就会看到一个红
          色的正方形。乍看上去,与使用绘图 API 所画的图形没什么不同,但是要知道这并不是矢
          量图绘制法:填充一个红色的正方形。这是张位图图像,在位图中每一个像素都要分别指定
          而且是可变的。事实上,每一个像素值都可以使用 getPixel,getPixel32 和
          setPixel,setPixel32 进行读取和设置。两个版本的不同之处在于 getPixel 和 setPixel
          使用 24 位色彩值忽略了 alpha 通道,而 “32”版的则使用 32 位色彩值其中包括了透明
          度信息。让我们来做个例子,制作一个简朴的喷漆工具,就像所有位图喷漆程序一样。
          这里是文档类,SprayPaint.as:
          package {
          import flash.display.Sprite;
          import flash.display.Bitmap;
          import flash.display.BitmapData;
          import flash.events.MouseEvent;
          import flash.events.Event;
          import flash.filters.BlurFilter;
          public class SprayPaint extends Sprite {
          private var canvas:BitmapData;   72
          private var color:uint;
          private var size:Number = 50;
          private var density:Number = 50;
          public function SprayPaint() {
          init();
          }
          private function init():void {
          canvas = new BitmapData(stage.stageWidth,
          stage.stageHeight,
          true, 0x00000000);
          var bmp:Bitmap = new Bitmap(canvas);
          addChild(bmp);
          stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
          stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
          }
          private function onMouseDown(event:MouseEvent):void {
          color = Math.random() * 0xffffff + 0xff000000;
          addEventListener(Event.ENTER_FRAME, onEnterFrame);
          }
          private function onMouseUp(event:MouseEvent):void {
          removeEventListener(Event.ENTER_FRAME, onEnterFrame);
          }
          private function onEnterFrame(event:Event):void {
          for (var i:int = 0; i < density; i++) {
          var angle:Number = Math.random() * Math.PI * 2;
          var radius:Number = Math.random() * size;
          var xpos:Number = mouseX + Math.cos(angle) * radius;
          var ypos:Number = mouseY + Math.sin(angle) * radius;
          canvas.setPixel32(xpos, ypos, color);
          }
          }
          }
          }
          这也许是目前为止最复杂的代码,但除了 BitmapData 的内容外,其它的知识前面都讲
          过,只不过又使用了一遍而已。一步步来看,首先,创建了一些类变量,包括 canvas 变量,
          用于存放 BitmapData 的实例。创建的实例尺寸等于舞台的尺寸,并使用透明的背景色。然
          后使用 canvas 创建一个位图,并加入到显示列表。
          鼠标事件处理函数中选择了一个随机的颜色,并且带有添加和删除 enterFrame 事件处理函
          数的功能。我们来回忆一下三角学,首先,从 0 到 Math.PI * 2 中计算出一个随机的角度,
          不要忘记使用弧度制表示,相当于随机的 360度。然后,计算出一个随机的半径后,再使用
          三角函数将半径和角度转换为 x,y 值。最后使用 setPixel32 以鼠标位置加上随机的 x,y
          值的像素点设置为喷漆色,每一次开始喷漆时随机决定颜色。在这个例子中有一个 for 循
          环,每一帧都会进行循环,每次循环多少次由 density 的值决定。 color 的值为24 位的
          色彩值,然后加上 0xFF000000,为的是设置 alpha 通道为完全不透明,如果没有加上这个
          值,那么所有的颜色就都为透明的。如果用 0xFFFFFFFF 乘以 Math.random(),那么颜色的
          透明度是随机的,也许是你想要的,但不是我想要的。通过改变 density 和 size 的值再
          测试一下,看看会有些什么不同的效果。大家也许已经想到如何让用户来控制改变这些参数
          了。
          刚刚看到这个程序时,你也许会想,“真是小题大作,完全可以用绘图 API 或通过加 73
          载小影片剪辑并改变颜色来实现”。是的,完成可以这么做,但是如果使用绘图 API 绘出
          成千上万的独立图像后,会发习画得越多,速度越慢。画过几百个图形后,慢下来的速度会
          变得非常明显,这个程序也就费掉了,使用加载影片剪辑的方式也是如此。但是,使用位图
          就完全不同了,我们可以使用这个程序喷上一天,都不影响程序的速度或效率。
          如果想看到更酷的效果,就把下面一行代码加在位图对象 bmp 的后面:
          bmp.filters = [new BlurFilter(2, 2, 3)];
          在位图中使用模糊滤镜比在矢量图中使用效果更加明显。 当然, 设置像素是 BitmapData
          对象能做的最简朴的操作之一。除了获取和设置像素,BitmapData 对象还有其它二十多种
          方法,这些方法可用来复制像素,设置阈值,分解,合并,滚动,等等。我个人最喜欢的一
          个是 perlinenoise 方法,该函数允许我们创建一个随机的有组织的图案。对于制造烟,云
          和水波纹效果都非常有用。有兴趣的话大家可以试验一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值