Рисование контуров вокруг органических фигур - PullRequest
3 голосов
/ 21 марта 2010

Одна вещь, которая кажется особенно простой в Flash IDE, но трудной для кода, - это наметить органическую форму. В IDE вы можете просто использовать инструмент чернильницы, чтобы нарисовать обводку вокруг чего-либо. Использование ничего, кроме кода, кажется гораздо сложнее. Один из методов, которые я видел, - это добавить светящийся фильтр к рассматриваемой фигуре и просто возиться с силой. Но что, если я хочу показать только контур?

Что я хотел бы сделать, это собрать все точки, которые составляют край фигуры, а затем просто соединить точки. На самом деле я дошел до того, что собрал все точки с помощью скрипта быстрого и грязного обнаружения краев, который я написал. Так что теперь у меня есть Вектор всех точек, которые составляют мою форму. Как мне соединить их в правильной последовательности, чтобы она действительно выглядела как оригинальный объект?

Для всех, кто интересуется здесь, мой скрипт обнаружения краев:

</p> <pre><code> // 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); } } } }

1 Ответ

2 голосов
/ 21 марта 2010

В настоящее время невозможно проанализировать форму того, что вы нарисовали во время разработки (то есть выяснить, где находятся углы всех линий и заливок), поэтому единственный хороший способ нарисовать контур вокруг произвольной формы - это растровый эффект. Однако то, как вы это делаете, вероятно, не будет плодотворным. Flash дает вам несколько способов обработки растровых изображений, но все, что включает в себя циклическую обработку каждого пикселя, обычно оказывается недостаточно быстрым для использования во время выполнения.

Скорее, я бы выбрал один из двух подходов: лучшим и самым простым будет использование встроенных фильтров. Как вы говорите, обычно, когда люди хотят нарисовать контур, они используют светящийся фильтр с большой силой и коротким радиусом. Если вы хотите показать только контур, отметьте свойство knockout. (Вы можете сделать это в скрипте или в IDE.) Если вам не нравится то, что вы получаете с этим, вы можете попробовать смешать фильтры - скажем, добавить размытие до или после свечения. Или вы можете использовать код для генерации эффекта свечения в пустое растровое изображение, а затем вы можете обрабатывать результат различными способами - например, с помощью BitmapData.threshold, который, как я обнаружил, очень мощный. В любом случае, я бы поиграл с этим некоторое время и убедился, что это действительно не решит вашу проблему, прежде чем вы попробуете что-то другое, потому что это, безусловно, самое простое решение.

Другой вариант - PixelBender. Это функция, которая позволяет вам определять пользовательский фильтр на C-подобном языке, который вы предварительно компилируете, а затем загружаете в ваш Flash-фильм и применяете к рассматриваемому растровому изображению. Процесс очень похож на программирование фильтра фотошопа. Это дает вам полный контроль над тем, какую обработку вы хотите выполнять с растровым изображением, но требует, чтобы вы работали вне Flash и вне ActionScript.

Переход к текущему маршруту и ​​ручная обработка пикселей - это, конечно, третий вариант, но вопрос в том, действительно ли вы делаете то, что не могли сделать в обычном или пользовательском фильтре. Если вы действительно хотите закончить то, что у вас есть, вы можете попробовать создать новое прозрачное растровое изображение, и для каждой точки, захваченной в приведенном выше коде, нарисуйте белую точку (с setPixel32) в этой точке. Это даст вам пиксельный контур, который вы, вероятно, захотите затем размыть или обработать другим способом. Но на самом деле вы получите нечто очень похожее на то, что вы могли бы получить с обычным светящимся фильтром, и это займет намного больше времени.

...