2010-03-21 61 views
3

有一件事情在Flash IDE中看起来特别容易,但在代码中很难做到的是勾画出有机形状。在IDE中,您可以使用墨水桶工具在某物周围画一个中风。使用任何东西,但代码似乎更棘手。我见过的一种方法是在所讨论的形状中添加一个辉光过滤器,只是混淆了强度。但是如果我只想显示轮廓呢?在有机形状周围绘制轮廓

我想要做的是收集构成形状边缘的所有点,然后连接点。我实际上已经用我编写的一个快速和肮脏的边缘检测脚本来收集所有的点。所以现在我有一个矢量化妆的所有要点。我如何以适当的顺序连接它们,使它看起来像原始对象?

对于任何人谁是有兴趣的,这里是我的边缘检测脚本:

  // Create a new sprite which we'll use for our outline 
     var sp:Sprite = new Sprite(); 
     var radius:int = 50; 
     sp.graphics.beginFill(0x00FF00, 1); 
     sp.graphics.drawCircle(0, 0, radius); 
     sp.graphics.endFill(); 
     sp.x = stage.stageWidth/2; 
     sp.y = stage.stageHeight/2; 

     // Create a bitmap data object to draw our vector data 
     var bmd:BitmapData = new BitmapData(sp.width, sp.height, true, 0); 

     // Use a transform matrix to translate the drawn clip so that none of its 
     // pixels reside in negative space. The draw method will only draw starting 
     // at 0,0 
     var mat:Matrix = new Matrix(1, 0, 0, 1, radius, radius); 
     bmd.draw(sp, mat); 

     // Pass the bitmap data to an actual bitmap 
     var bmp:Bitmap = new Bitmap(bmd); 

     // Add the bitmap to the stage 
     addChild(bmp); 

     // Grab all of the pixel data from the bitmap data object 
     var pixels:Vector.<uint> = bmd.getVector(bmd.rect); 

     // Setup a vector to hold our stroke points 
     var points:Vector.<Point> = new Vector.<Point>; 

     // Loop through all of the pixels of the bitmap data object and 
     // create a point instance for each pixel location that isn't 
     // transparent. 
     var l:int = pixels.length; 
     for(var i:int = 0; i < l; ++i) 
     { 
      // Check to see if the pixel is transparent 
      if(pixels[i] != 0) 
      { 
       var pt:Point; 

       // Check to see if the pixel is on the first or last 
       // row. We'll grab everything from these rows to close the outline 
       if(i <= bmp.width || i >= (bmp.width * bmp.height) - bmp.width) 
       { 
        pt = new Point(); 
        pt.x = int(i % bmp.width); 
        pt.y = int(i/bmp.width); 
        points.push(pt); 
        continue; 
       } 

       // Check to see if the current pixel is on either extreme edge 
       if(int(i % bmp.width) == 0 || int(i % bmp.width) == bmp.width - 1) 
       { 
        pt = new Point(); 
        pt.x = int(i % bmp.width); 
        pt.y = int(i/bmp.width); 
        points.push(pt); 
        continue; 
       } 

       // Check to see if the previous or next pixel are transparent, 
       // if so save the current one. 
       if(i > 0 && i < bmp.width * bmp.height) 
       { 
        if(pixels[i - 1] == 0 || pixels[i + 1] == 0) 
        { 
         pt = new Point(); 
         pt.x = int(i % bmp.width); 
         pt.y = int(i/bmp.width); 
         points.push(pt); 
        } 
       } 
      } 
     } 

回答

2

目前这是不可能的内省,你在设计时画的东西的形状(即找出所有的角落线和填充是),因此围绕任意形状绘制轮廓的唯一好方法就是作为位图效果。然而,你如何去做它可能不会取得成果。 Flash为您提供了几种处理位图的方法,但任何涉及遍历每个像素的内容通常都不会在运行时足够快地使用。

相反,我会采取以下两种方法之一:最好也最简单的方法是使用内置过滤器。正如你所说,通常当人们想绘制一个轮廓时,他们会使用强度大,半径小的辉光滤镜。如果只想显示轮廓,请检查knockout属性。 (您可以在脚本或IDE中执行此操作。)如果您不喜欢使用此功能,则可以尝试使用混合滤镜 - 例如,在发光之前或之后添加模糊处理。或者,您可以使用代码来将空白效果生成空白位图,然后您可以用各种方式处理结果 - 例如,我发现它的功能非常强大,例如BitmapData.threshold。无论如何,我会玩一会儿,并且确保它在你尝试别的之前不会解决你的问题,因为它是迄今为止最简单的解决方案。

另一种选择是PixelBender。这是一项功能,可让您以C语言定义自定义过滤器,您可以预编译并加载到Flash影片中,并将其应用于有问题的位图。这个过程与编辑一个photoshop过滤器非常相似。这使您可以完全控制要对位图执行的处理类型,但它要求您在Flash和外部动作之外工作。

去当前的路线和手动处理像素当然是第三种选择,但问题是,你是否真的做了任何你不能在正常或自定义过滤器中做的事情。如果你真的想完成你已经完成的任务,你可以尝试制作一个新的透明位图,并且对于你在上面的代码中捕获的每个点,在那个点上绘制一个白点(带有setPixel32)。这会给你一个像素化的轮廓,你可能会想要模糊或以其他方式处理。但是,真的,你将会得到一些非常类似于普通辉光滤波器的东西,而且这需要更长的时间。

+0

我正在测试我用来获取边缘的代码,除非我做错了它似乎很快。根据格兰特斯金纳的测试工具,它可以在9.63ms或9631ms内运行1000次迭代。如果有人有时间仔细检查,我将不胜感激。我使用的代码如下:http://pastebin.com/s59FPGvB – 2010-03-21 17:46:37

+0

在空位图中生成效果可能与我之后的效果最接近。你只需要将原始位图中的变换对象应用到空白对象上?这甚至工作吗? – 2010-03-21 18:13:57