辣鸡

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

        在之前的两篇文章中我们介绍了PerlinNoise的两种用途:创建云雾等自然效果以及用作随机数提供源。那么在这一章中,贫道将隆重介绍一位perlinNoise的好基友:DisplacementMapFilter

 

神马是DisplacementMapFilter

        DisplacementMapFilter是一种滤镜,使用它可以让一张BitmapData的像素发生偏移,产生出一种类似于扭曲的效果。山羊书(《Foundation  Actionscript3.0 Image Effect》)中,在第四章Advanced Bitmap Manipulation中的Displace pixels这一节中对此滤镜有着详细的介绍,下面先引用其一张截图:

        从上图中我们可以看到,以左边这张图作为滤镜的像素提供源产生一个DisplacementMapFilter后应用于右侧的一张格子图上面,会出现一个圆形的像素偏移区域。那么DisplacementMapFilter这个滤镜的工作原理是怎么样的呢?我们应该如何使用它?

        在山羊书中对DisplacementMapFilter滤镜工作原理做了非常详细的剖析,但是你现在在看我的文章,不可能还拿出山羊书来翻一翻先,好吧,下面我简单地翻译并概括一下山羊书中对其的解释。首先我们来看DisplacementMapFilter滤镜的参数设置:

public function DisplacementMapFilter(mapBitmap:BitmapData = null, mapPoint:Point = null, componentX:uint = 0, componentY:uint = 0, scaleX:Number = 0.0, scaleY:Number = 0.0, mode:String = "wrap", color:uint = 0, alpha:Number = 0.0)

mapBitmap:BitmapData (default = null) — 包含置换映射数据的 BitmapData 对象。

mapPoint:Point (default = null) — 一个值,它包含目标显示对象的左上角相对于映射图像左上角的偏移量。

componentX、Y:uint (default = 0) — 说明在映射图像中使用哪个颜色通道来置换 x ,y 结果。 可能的值为 BitmapDataChannel 常数。

scaleX、Y:Number (default = 0.0) — 用于缩放映射计算的 x , y 置换结果的乘数。

mode:String (default = "wrap") — 滤镜模式。 可能的值为 DisplacementMapFilterMode 常数。

color:uint (default = 0) — 指定对于超出范围的替换应用什么颜色。 置换的有效范围是 0.0 到 1.0。如果 mode 设置为 DisplacementMapFilterMode.COLOR,则使用此参数。

alpha:Number (default = 0.0) — 指定对于超出范围的替换应用什么 Alpha 值。 它被指定为 0.0 到 1.0 之间的标准值。例如,.25 设置透明度值为 25%。 如果 mode 设置为 DisplacementMapFilterMode.COLOR,则使用此参数。

        当你传入一个BitmapData对象作为DisplacementMapFilter的第一个参数mapBitmap的话,该BitmapData对象实际上就成了一个像素提供源,DisplacementMapFilter内部会根据一个公式来计算出滤镜应用结果的像素值,该公式可以表示为:

dstPixel[x, y] = srcPixel[x + ((componentX(x, y) - 128) * scaleX) / 256, y + ((componentY(x, y) - 128) *scaleY) / 256)

设dstPixel[x, y]为滤镜应用结果于(x,y)位置处的像素值,该像素值应与像素提供源srcPixle于(x + ((componentX(x, y) - 128) * scaleX) / 256, y + ((componentY(x, y) - 128) *scaleY) / 256)位置的像素值一致。componentX、Y指某一个颜色通道。

        下面我们一起来算一次。假设我传入DisplacementMapFilter中的componentX参数为BitmapDataChannel.RED,scaleX值为10, 而像素源mapBitmap于(0,0)位置的红色值恰好为0x80(转换为十进制是128),那么x + ((componentX(x, y) - 128) * scaleX) / 256 = 0 + ((componentX(x, y)  - 128) * 10) / 256 = 0 + ( (128 - 128) * 10  ) / 256 = 0

再假设我同样使用了红色通道作为componenY , scaleY 值为10, 那么后面那个算式y + ((componentY(x, y) - 128) *scaleY) / 256得出的计算结果也一样是0.

这意味着什么呢?这意味着此时滤镜应用结果在(0,0)位置上的颜色是取自像素提供源(0,0)位置上的颜色的。若像素源mapBitmap于(0,0)位置的红色值为0xFF(转换为十进制为255)的话,计算结果将变成(5,5),这意味着此时滤镜应用结果在(0,0)位置上的颜色是取自像素提供源(5,5)位置上的颜色。那若是像素源mapBitmap于(0,0)位置的红色值为0x00(转换为十进制为0)的话,计算结果将变成(-5,-5),这时候怎么办呢?DisplacementMapFilter会根据其mode参数来决定如何取(-5,-5)这个超出边界的像素。下面是四种可选的mode介绍:

 

  • DisplacementMapFilterMode.WRAP -- 将置换值折返到源图像的另一侧。
  • DisplacementMapFilterMode.CLAMP -- 将置换值锁定在源图像的边缘。
  • DisplacementMapFilterMode.IGNORE -- 如果置换值超出了范围,则忽略置换并使用源像素。
    • DisplacementMapFilterMode.COLOR -- 如果置换值在图像之外,则替换 color  alpha 属性中的值。

扭起来吧少年

        介绍完了好基友DisplacementMapFilter童鞋,接下来就应该看看它能怎样配合perlinNoise来产生“扭扭更健康”的目标。先看一个水波纹的例子,该例子出自

http://www.thetechlabs.com/tech-tutorials/flash/create-real-water-effects-with-flash-cs4-actionscript-30/

        当然,这个例子也是纯英文的,英文不好的童鞋只需要看看它的成果演示就够了。我这里只对它头一个例子做一些解释,若是打不开上面给的地址,可以看这里(点击图片浏览):

        至于实现原理,说简单也简单:生成不规则的波纹靠的是perlinNoise,让波纹产生扭曲则靠的是之前介绍的DisplacementMapFilter,最后让波纹不停地滚动,就得靠不停地滚动使用perlinNoise生成的杂点图像并不停地为目标图片更新滤镜了。在上面给出的文章地址中,老外作者使用了每帧改变perlinNoise的offsets参数来实现滚动:

var bm:BitmapData=new BitmapData(backImg1.width, backImg1.height);
var disp:DisplacementMapFilter = new DisplacementMapFilter(bm,new Point(0,0),1,2,10,60);
var pt1:Point = new Point(0,0);
var pt2:Point = new Point(0,0);
var perlinOffset:Array = [pt1, pt2];

addEventListener(Event.ENTER_FRAME, onFrame);
function onFrame(evt:Event):void {
  perlinOffset[0].x +=1;
  perlinOffset[1].y +=0.1;
  bm.perlinNoise(45,9,2,50,true,false, 7,true,perlinOffset);
  backImg1.filters=[disp];
}

 这样写固然简单,但是在之前的噪声的魅力(上)这篇文章中我们提到过,使用这种改变offests参数的方式来滚动柏林杂点图效率低下,因为它每帧都要调用perlinNoise方法来生成新图。那么更加高效的方式之前也在云飘动的例子中提到过,就是使用一种类似传送带的方法(也可以叫做卡马克卷轴算法)来做到。这里就不多解释了,我直接把水波纹的特效做成了一个单独组件SWaterWaveEffect,并收录在了我的SComponent系列中,列位可以去置顶的帖子里下载源码进行查看。

posted on 2013-07-17 11:49  辣鸡  阅读(329)  评论(0编辑  收藏  举报