В этом уроке мы будем создавать файл класса, который создает стилизованную маску для любого DisplayObject
. Маска будет основана на шуме Перлина и создаст эффект растущих отверстий, которые постепенно «разъедают» DisplayObject
до тех пор, пока он не будет полностью скрыт. Попутно мы изучим некоторые из более продвинутых методов, доступных с использованием BitmapData
.
Предварительный просмотр финального эффекта
Давайте посмотрим на эффект, который мы после. SWF ниже показывает это в виде перехода между изображениями.
Вы можете видеть, что изображения как бы тают друг на друга, случайным, но органичным образом. Новые изображения начинают расти из маленьких пятен, которые в конечном итоге заполняют весь холст. Этот эффект основан на Perlin Noise .
Что такое шум Perlin?
Perlin Noise назван в честь Кена Перлина, который разработал эту модель шума для использования в приложениях компьютерной графики. Чтобы лучше понять это, давайте сначала посмотрим на обычный шум.
Шум в компьютерной графике — это просто случайное изображение. Если вы откроете Photoshop, создадите новое изображение и заполните холст белым, вы сможете увидеть эффекты обычного шума, выбрав меню « Фильтр»> «Шум»> «Добавить шум…» . Установите значение 100% и при необходимости включите параметр «Монохроматический». Эффект будет выглядеть как статический:
Это можно сделать, просто установив каждый пиксель изображения в случайное количество оттенков серого (это немного упрощает, но давайте будем простыми).
Шум Перлина, с другой стороны, имеет более органичное ощущение, поэтому он был разработан. Вы можете понять это в Photoshop, создав новый документ и выбрав « Фильтр»> «Рендеринг»> «Облака» . Вы сразу увидите разницу:
Вы можете видеть, что каждый пиксель имеет влияние на своих соседей; темные области сгруппированы вместе, что придает ему более гладкий вид.
Из-за «контролируемой случайности» шума Перлина, он имеет множество приложений в компьютерной графике, от текстур в трехмерном моделировании до моделирования дыма и огня. Мы воспользуемся «группировкой яркости» шума Перлина, чтобы отобразить дыры в нашей маске.
В Википедии есть небольшая статья о Perlin Noise . В этой статье подробно рассматривается шум в целом и шум Перлина в частности, если вы хотите узнать больше о механике процесса.
Шаг 1: Создать проект
Чтобы создать наш эффект, мы напишем класс, который в конечном итоге будет обрабатывать графику, а также тестовый файл, в котором можно увидеть, как продвигается наш эффект.
Начните с простого создания новой папки на жестком диске с именем Perlin Mask для размещения всех файлов, связанных с проектом.
Шаг 2. Создайте файл Flash
Open Flash Professional (для написания этого руководства использовался CS4, но на шаге 15 вам нужно будет использовать вектор, который доступен только в Flash Pro CS4 +; в конце этого шага я предоставил альтернативу) и создать новый файл ActionScript 3.0 (перейдите в меню « Файл»> «Создать» и выберите « ActionScript 3.0 » из списка).
Сохраните этот файл как PerlinMask.fla в папке вашего проекта.
Примечание. При желании вы можете использовать стартовый файл, который находится в папке test-start пакета загрузки. Этот FLA уже содержит изображение, поэтому вы можете пропустить следующий шаг, если вам не нравится идея импорта и использования ваших собственных изображений.
Шаг 3: Импортируйте изображение
Неважно, с каким изображением, только если у нас есть что работать во Flash. Увеличенное изображение обеспечит больший холст для просмотра эффекта, но слишком большое, и вы можете столкнуться с проблемами производительности.
Выберите меню «Файл»> «Импорт»> «Импортировать в рабочую область…» , перейдите к изображению на жестком диске и выберите его для переноса во Flash. (Естественно, не стесняйтесь изменить его размер в Photoshop или другом графическом редакторе, прежде чем импортировать его во Flash.)
Мы хотим обратиться к изображению с помощью ActionScript, поэтому нам придется связать его в мувиклип. Выбрав изображение, нажмите F8 и убедитесь, что диалоговое окно «Преобразовать в символ» выглядит следующим образом:
Убедитесь, что выбран левый верхний пункт регистрации.
Наконец, дайте экземпляру символа имя экземпляра « image_mc », введя его на панели «Свойства» для изображения.
Шаг 4. Создайте класс документа
Создайте новый файл AS в папке вашего проекта и назовите его PerlinTest.as . Это будет класс документа для нашего FLA. Эффект маски шума Perlin не будет содержаться в этом файле; скорее, он будет использовать класс, который мы создаем для эффекта, в целях тестирования эффекта при его создании. В конечном итоге это послужит примером того, как использовать эффект в других проектах.
Введите следующий код в файл, который вы только что создали:
1
2
3
4
5
6
7
8
|
package {
import flash.display.Sprite;
public class PerlinTest extends Sprite {
public function PerlinTest() {
trace(«PerlinTest»);
}
}
}
|
Вернувшись в файл Flash, убедитесь, что ничего не выбрано, затем введите PerlinTest в поле « Класс» на панели «Свойства», чтобы установить класс PerlinTest
в качестве класса документа для FLA.
Запустите файл Flash (« Управление»> «Тестировать ролик»> «Тест» или « Command / Control-Enter» ), и вы увидите след на панели «Вывод»:
Шаг 5: Создайте класс PerlinMask
Мы скоро вернемся к классу документов, но мы все еще создаем файлы для нашего маленького проекта.
В папке проекта создайте небольшую иерархию папок, начиная с com . Затем внутри «com» создайте папку activetuts . Наконец, внутри этого создайте папку с именем « эффектами »
Создайте еще один текстовый файл и сохраните его как PerlinMask.as в папке эффектов, которую вы только что создали. Добавьте следующий код для начала:
1
2
3
4
5
6
7
|
package com.activetuts.effects {
public class PerlinMask {
public function PerlinMask() {
trace(«PerlinMask»);
}
}
}
|
Шаг 6. Создание экземпляра PerlinMask
В PerlinTest.as мы создадим экземпляр класса PerlinMask
мы только что создали, и протестируем его, чтобы убедиться, что все правильно подключено.
Ниже приведен полный класс PerlinTest с выделенными на этом этапе строками:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
package {
import flash.display.Sprite;
import com.activetuts.effects.PerlinMask;
public class PerlinTest extends Sprite {
private var _mask:PerlinMask;
public function PerlinTest() {
trace(«PerlinTest»);
_mask = new PerlinMask();
}
}
}
|
Обратите внимание, что нам нужно импортировать класс (строка 3), затем мы объявляем свойство экземпляра (строка 7), чтобы позже мы могли ссылаться на маску. Наконец, мы просто создаем новый экземпляр класса PerlinMask
(строка 11).
Запустите фильм снова, и теперь у вас должно быть два следа, указывающих, что мы успешно создаем объект PerlinMask
.
Шаг 7: Дайте PerlinMask
что-то PerlinMask
Теперь мы начинаем серьезно работать над эффектом. Вернитесь к PerlinMask.as, и мы начнем с добавления свойства для хранения объекта DisplayObject
мы хотим замаскировать. Вот полный код класса с выделенными новыми строками:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
package com.activetuts.effects {
import flash.display.*;
public class PerlinMask {
private var _target:DisplayObject;
public function PerlinMask(target:DisplayObject) {
_target = target;
}
}
}
|
В конечном итоге target
будет замаскирована нашей шумовой маской Perlin. Дальнейшее тестирование потребует установки этого свойства, поэтому прежде чем идти дальше, вернитесь в файл PerlinTest.as и обновите строку, в которой мы создаем объект PerlinMask
:
1
2
3
|
public function PerlinTest() {
_mask = new PerlinMask(image_mc);
}
|
Мы просто PerlinMask
именованный экземпляр на сцене конструктору PerlinMask
.
Обратите внимание, что я пользуюсь возможностью удалить линии trace
пока мы редактируем код.
Шаг 8. Создание растрового изображения для использования в качестве маски
Чтобы замаскировать target
объект, нам нужен еще один объект DisplayObject
. Природа использования шума Перлина в качестве нашей маски означает, что нам придется использовать объект Bitmap
в качестве маски. И для работы с Bitmap
в коде нам также необходим объект BitmapData
. Следующий код поможет нам настроить эти элементы:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
package com.activetuts.effects {
import flash.display.*;
import flash.geom.*;
public class PerlinMask {
private var _target:DisplayObject;
private var _mask:Bitmap;
private var _maskPixels:BitmapData;
private var _rect:Rectangle;
public function PerlinMask(target:DisplayObject) {
_target = target;
_rect = new Rectangle(0, 0, _target.width, _target.height);
_maskPixels = new BitmapData(_rect.width, _rect.height, true, 0xFF000000);
_mask = new Bitmap(_maskPixels);
_mask.x = _target.x;
_mask.y = _target.y;
_target.parent.addChild(_mask);
}
}
}
|
Есть дополнительный оператор import
поэтому мы можем использовать Rectangle
s, и установить три новых свойства. Свойства Bitmap
и BitmapData
вы знали, пришли, но цель Rectangle
теперь не кажется очевидной. Мы будем использовать его позже, и имеет смысл пойти дальше и настроить его сейчас, поскольку мы хотим использовать измерения для объекта BitmapData
. Короче говоря, Rectangle
будет использоваться для определения области, на которую мы хотим повлиять при выполнении наших эффектов BitmapData
. Итак, мы устанавливаем размер нашего target
объекта и используем эти размеры.
После того, как мы создали наш объект BitmapData
, мы создаем объект Bitmap
чтобы мы могли отображать пиксели (здесь я не буду вдаваться в подробности, но объект BitmapData
— это просто группа пикселей, или, скорее, данные, представляющие эти пикселей. Bitmap
объект — это своего рода объект DisplayObejct
предназначенный для отображения пикселей. Поэтому подача Bitmap
некоторых пикселей в виде BitmapData
является способом просмотра этих пикселей).
Следующие три строки могут показаться немного странными. Но поскольку мы хотим, чтобы Bitmap
маскировало target
, нам необходимо убедиться, что Bitmap
находится в том же месте и в том же контейнере, что и target
. Таким образом, мы помещаем их в те же координаты, а затем добавляем Bitmap
в список отображения, добавляя его к родительскому target
, который помещает его в тот же DisplayObjectContainer
что и target
. Окончательный результат заключается в том, что два объекта должны быть одинакового размера и в одинаковом положении.
На самом деле, если вы запустите фильм сейчас, вы должны увидеть, что ваше изображение скрыто черным прямоугольником:
Шаг 9. Создайте повторно используемые свойства для операций BitmapData
Дальше у нас есть работа по дому. Наши будущие манипуляции с пикселями потребуют использования нескольких значений, которые будут отправлены различными способами. Многие из этих значений будут оставаться неизменными каждый раз, когда мы выполняем манипуляции, поэтому мы также можем создавать свойства для их хранения. Что касается кешированных значений в свойствах, будет проще просто искать существующие значения, а не создавать новые значения каждый раз, когда они нам понадобятся.
В PerlinMask.as добавьте следующие новые свойства вместе с начальными значениями, установленными в конструкторе (выделены новые строки):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package com.activetuts.effects {
import flash.display.*;
import flash.filters.*;
import flash.geom.*;
public class PerlinMask {
private var _target:DisplayObject;
private var _mask:Bitmap;
private var _maskPixels:BitmapData;
private var _rect:Rectangle;
private var _point:Point;
private var _blur:BlurFilter;
private var _operation:String;
public function PerlinMask(target:DisplayObject) {
_target = target;
_rect = new Rectangle(0, 0, _target.width, _target.height);
_maskPixels = new BitmapData(_rect.width, _rect.height, true, 0xFF000000);
_mask = new Bitmap(_maskPixels);
_mask.x = _target.x;
_mask.y = _target.y;
_target.parent.addChild(_mask);
_point = new Point(0, 0);
_blur = new BlurFilter(16, 16, 2);
_operation = «<«;
}
}
}
|
Мы вернемся к тому, что они делают позже; Достаточно сказать, что мы будем использовать их в методах, вызываемых для объектов BitmapData
.
На этом этапе не нужно много тестировать, кроме компиляции, чтобы убедиться, что ошибки не были внесены. Через несколько шагов у нас будет что-то новое.
Шаг 10: создай источник шума Perlin
Природа нашего эффекта фактически потребует другого объекта BitmapData
. Эта вторая BitmapData
будет там, где мы создадим шум Перлина. Уже созданный нами объект BitmapData
, который отображается объектом Bitmap
, в конечном итоге получит пиксели на основе этого другого объекта BitmapData
. Сейчас это может показаться излишним, но оно нам понадобится.
На данный момент нам просто нужно объявить свойство, а затем создать новое BitmapData
для него в конструкторе:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class PerlinMask {
private var _target:DisplayObject;
private var _mask:Bitmap;
private var _maskPixels:BitmapData;
private var _noise:BitmapData;
private var _rect:Rectangle;
private var _point:Point;
private var _blur:BlurFilter;
private var _operation:String;
public function PerlinMask(target:DisplayObject) {
_target = target;
_rect = new Rectangle(0, 0, _target.width, _target.height);
_maskPixels = new BitmapData(_rect.width, _rect.height, true, 0xFF000000);
_mask = new Bitmap(_maskPixels);
_mask.x = _target.x;
_mask.y = _target.y;
_target.parent.addChild(_mask);
_noise = new BitmapData(_rect.width, _rect.height, false, 0xFFFFFF);
_point = new Point(0, 0);
_blur = new BlurFilter(16, 16, 2);
_operation = «<«;
}
}
|
Просто собственность и ее стоимость. Обратите внимание, что этот BitmapData
непрозрачен ( false
третий параметр); как упоминалось ранее, мы создаем шум Perlin в этом BitmapData
, и поскольку сам шум Perlin непрозрачен, нам не нужна прозрачная битовая карта. Вещи будут выполнять прикосновение быстрее с непрозрачными BitmapData
а не с прозрачными.
Шаг 11: Шуметь
Наконец, мы можем создать шум Перлина! Мы перенесем создание шума в другой метод, называемый reseed()
. Этот метод просто создаст шум Перлина. Мы помещаем его в отдельный метод, чтобы его можно было вызывать извне. Каждый раз, когда генерируется шум Перлина, он будет использовать новое случайное начальное число, поэтому эффект будет отличаться каждый раз. Нам нужно убедиться, что этот метод вызывается из конструктора, чтобы убедиться, что шум готов к работе при первом создании объекта.
В классе PerlinMask
добавьте вызов reseed()
, затем добавьте этот метод:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public function PerlinMask(target:DisplayObject) {
_target = target;
_rect = new Rectangle(0, 0, _target.width, _target.height);
_maskPixels = new BitmapData(_rect.width, _rect.height, true, 0xFF000000);
_mask = new Bitmap(_maskPixels);
_mask.x = _target.x;
_mask.y = _target.y;
_target.parent.addChild(_mask);
_noise = new BitmapData(_rect.width, _rect.height, false, 0xFFFFFF);
_point = new Point(0, 0);
_blur = new BlurFilter(16, 16, 2);
_operation = «<«;
reseed();
}
public function reseed():void {
var seed:int = Math.random() * 32000;
_noise.perlinNoise(_rect.width, _rect.height, 2, seed, false, false, 7, true);
_maskPixels.copyPixels(_noise, _rect, _point);
}
|
Метод reseed
находится в нескольких шагах от завершения. Третья строка метода ( copyPixels
) не является окончательной, она просто используется для того, чтобы мы взяли шум Perlin из второй BitmapData
( _noise
) и скопировали пиксели в первую BitmapData
( _maskPixels
). Это позволяет нам видеть шум Перлина, потому что эти первые BitmapData
видны через объект Bitmap
.
Идите и протестируйте фильм; вы должны увидеть что-то вроде (но не совсем) следующее:
Итак, давайте объясним параметры perlinNoise
.
Первые два параметра — это ширина и высота. Это связано с частотой, и эти значения регулируют эту частоту в зависимости от размера изображения. Большие значения будут «распространять» эффект. Если вы _rect.width*10
и _rect.height*10
, вы потеряете много деталей, которые вы видите сейчас:
Если вы попробуете _rect.width/10
и _rect.height/10
, вы увидите меньшие «пулы» затенения:
Вы можете думать об этом как о каком-то параметре масштаба: чем выше значение, тем выше масштаб шума, чтобы мы были «увеличены» на крошечной части всего шаблона. Нижнее значение сделало нам шаг назад, чтобы мы могли видеть больше паттерна.
Возможно, вы захотите настроить это значение по своему вкусу, но вам следует настроить его в соответствии с размером целевой маски, а не с использованием каких-либо абсолютных значений, чтобы обеспечить согласованный эффект для различных размеров.
Третий параметр указан как «октавы» в документации. Он определяет, сколько генераторов шума использовать. Чем выше число, тем больше деталей. Вы увидите более тонкие линии, пронизывающие шум. Это похоже на несколько слоев шума, каждый из которых становится немного более тонким и тонким. Я нахожу, что 2 октавы дают эффект, которого я достиг: меньшее количество более крупных «пулов».
Для быстрого сравнения, вот шум Перлина, генерируемый с 4 октавами:
И 10 октав:
Четвертый параметр, seed
, является случайным семенем. Если бы это число было одинаковым каждый раз, мы бы получали одинаковый эффект каждый раз. Вот почему мы создаем значение как случайное целое число. Как только шум генерируется, мы используем его как есть, но если бы мы хотели многократно использовать эту маску, когда она анимировалась, то мы могли бы повторно заполнить шум, чтобы каждый раз получать новый эффект.
Пятый параметр дает нам возможность сгладить края, чтобы сгенерированный шум можно было объединить вместе. Это не то, что нам нужно, поэтому мы оставим это.
Шестой параметр указывает, следует ли использовать фрактальный шум. Включение этого создает более тонкий, более эффектный эффект, и не совсем то, что я искал в эффекте маски.
Седьмой параметр (где передается число 7) — это параметры канала. Это указывает, какие цветовые каналы использовать. Мое использование 7 является комбинацией каналов RGB. Я решил это путем экспериментов, и это, казалось, дало самый сильный контраст между самым высоким и самым низким значениями яркости в изображении.
Восьмой параметр указывает, следует ли поворачивать шум в оттенках серого. Мы собираемся использовать его как карту для альфы, поэтому желательна шкала серого. Если false
, вы сможете увидеть эффекты передачи различных параметров к предыдущему параметру.
Наконец, последний параметр (который не используется) — это массив точек. Эти точки являются смещением. Существует одно смещение для каждой октавы. Это дает вам несколько интересных вариантов; Обновление значений смещения позволяет плавно прокручивать шум. Прокручивая октавы независимо, вы можете создавать водные эффекты. Однако это не то, что нас интересует, и мы хотим, чтобы наши октавы были объединены в одну текстуру, поэтому мы проверяем, передав одну точку смещения в массиве, что все октавы используют одинаковое смещение.
Стоит отметить, что это руководство создает эффект, который один раз устанавливает шум Перлина и оставляет его в покое. Первоначально я играл с регенерированием шума в качестве анимации маски и манипулировал значениями смещения. В конце концов, результат был очень тонким, и я решил в пользу меньших накладных расходов, чтобы не создавать шум во время анимации. Тем не менее, это то, что нужно иметь в виду, если вы хотите настроить эффект самостоятельно.
Шаг 12: Используйте Порог, чтобы Ткнуть Отверстия в Шуме
Теперь мы будем использовать другой метод BitmapData
чтобы скопировать пиксели из шума Перлина в нашу маску Bitmap
, но только определенные пиксели. Метод threshold
позволяет нам выполнить сравнение для каждого пикселя в BitmapData
и, если условие выполнено, скопировать этот пиксель. Мы установим порог посередине, и вы увидите последствия этого.
Все еще работая в PerlinMask.as , нам нужно удалить строку в reseed()
которая копирует пиксели:
1
2
3
4
|
public function reseed():void {
var seed:int = Math.random() * 32000;
_noise.perlinNoise(_rect.width, _rect.height, 2, seed, false, false, 1, true);
}
|
Затем поместите вызов метода updateMask
(мы напишем этот метод далее) в самом конце конструктора:
1
2
3
4
5
6
7
|
_point = new Point(0, 0);
_blur = new BlurFilter(16, 16, 2);
_operation = «<«;
reseed();
updateMask();
}
|
И, наконец, напишите метод updateMask
:
1
2
3
|
private function updateMask():void {
_maskPixels.threshold(_noise, _rect, _point, _operation, 0xFF666666, 0, 0xFFFFFFFF, false);
}
|
Если вы сейчас запустите фильм, вы увидите, что у нас есть несколько случайных, органических фигур, покрывающих изображение, но эти части изображения просвечивают.
Вы можете поэкспериментировать с фактическим порогом, изменив пятый параметр. Например, установка его в 0xFF222222
порог и покрывает большую часть изображения черным.
В конце мы будем анимировать это пороговое значение, чтобы создать наш конечный эффект.
Если вам интересно, вот краткое изложение других параметров.
Первый параметр — это объект BitmapData
для которого запускается порог. Мы используем шум Перлина в качестве нашего источника.
Второй и третий параметры являются геометрическими свойствами. Прямоугольник определяет область исходного BitmapData
для прохождения через порог. Точка — это местоположение в целевом BitmapData
(в данном случае _maskPixels
) для размещения верхнего левого угла этого прямоугольника. Поскольку наш прямоугольник имеет тот же размер, что и наше изображение, и BitmapData
шумом Перлина, а точка установлена на (0,0)
, мы в основном копируем пиксели очень параллельным способом.
Четвертый параметр — _operation
. Эта String
сообщает threshold
методу, как запустить сравнение. Мы проходим «
Следующий параметр — это пороговое значение, используемое для сравнения. Это целое число ARGB (легче всего представить в шестнадцатеричной записи). Наш источник шума Perlin непрозрачен, поэтому канал «A» должен быть FF
. На этом этапе разработки мы жестко кодируем среднее значение для каналов «RGB» (помните, мы генерируем шум в оттенках серого).
Общий эффект между 4-м и 5-м параметрами заключается в том, что если данный пиксель в шуме Перлина меньше (или темнее) серого цвета 0x666666
, то он копируется в _maskPixels
. Пиксель копируется в то же место. Но это еще не все, о нет, это еще не все.
Пиксель не просто копируется напрямую. Шестой параметр — это цвет, используемый в копии. По умолчанию 0, и имейте в виду, что это другое значение ARGB, поэтому 0 полностью прозрачный черный. Если мы передадим непрозрачное значение цвета, вы увидите другие эффекты:
Изображение выше: порог с цветом 0x6600FF00 (полупрозрачный зеленый).
Седьмой параметр — это маска, используемая для выделения цветовых компонентов. Вы не увидите никаких изменений при использовании этого параметра в этом конкретном примере.
Последний параметр — это Boolean
значение, указывающее, следует ли копировать пиксели из исходного BitmapData
. Вы можете установить это значение true
прямо сейчас, чтобы понять, как выглядит шум и как он влияет на то, что копируется. Имейте в виду, что этот параметр предназначен для пикселей, которые не проходят пороговый тест, поэтому вы увидите более светлые пиксели, если установите его в значение true
.
Независимо от того, является ли этот параметр true
или false
, наш конечный результат для маски будет одинаковым. Вы можете оставить это в true
если вам нравится визуализация, но в конце вы не увидите ее.
Я не боюсь признать, что не до конца понимаю все, что здесь происходит; threshold
очень гибкий и мощный. Но, к счастью, эффект, который мне нужен, более прямолинеен, чем некоторые из более сложных манипуляций с цветом, которые вы можете выполнить с помощью этого метода.
Теперь ключ будет манипулировать фактическим порогом, который передается; когда это изменится, мы получим больше или меньше пикселей, скопированных в маску в зависимости от порога, а затем, анимируя это значение, мы сможем создать эффект растущего аморфного блоба, к которому мы стремимся.
Шаг 13: Создание percent
свойства
Мы хотим произвести настройку порога и, следовательно, эффекта маски, так же просто, как установить для свойства percent
значение от 0 до 1. Для этого потребуется частное свойство для хранения значения процента, открытый установщик и получатель и некоторая добавленная логика. updateMask
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
public class PerlinMask {
private var _target:DisplayObject;
private var _mask:Bitmap;
private var _maskPixels:BitmapData;
private var _noise:BitmapData;
private var _rect:Rectangle;
private var _point:Point;
private var _blur:BlurFilter;
private var _operation:String;
private var _percent:Number;
public function PerlinMask(target:DisplayObject) {
_target = target;
_rect = new Rectangle(0, 0, _target.width, _target.height);
_maskPixels = new BitmapData(_rect.width, _rect.height, true, 0xFF000000);
_mask = new Bitmap(_maskPixels);
_mask.x = _target.x;
_mask.y = _target.y;
_target.parent.addChild(_mask);
_noise = new BitmapData(_rect.width, _rect.height, false, 0xFFFFFF);
_point = new Point(0, 0);
_blur = new BlurFilter(16, 16, 2);
_operation = «<«;
reseed();
updateMask();
}
public function reseed():void {
var seed:int = Math.random() * 32000;
_noise.perlinNoise(_rect.width, _rect.height, 2, seed, false, false, 7, true);
}
private function updateMask():void {
var channelThreshold:uint = 0xFF * _percent;
var thresh:uint = 0xFF000000 + (channelThreshold << 16) + (channelThreshold << 8) + channelThreshold;
_maskPixels.threshold(_noise, _rect, _point, _operation, thresh, 0, 0xFFFFFFFF, true);
}
public function set percent(value:Number):void {
_percent = value;
updateMask();
}
public function get percent():Number {
return _percent;
}
}
|
Бизнес свойств должен быть довольно простым: мы объявляем свойство (строка 19) и создаем для него установщик и получатель (строки 53-60). updateMask
снова вызывает updateMask
, чтобы мы могли перерисовать маску с новым значением процента.
Однако новая логика в updateMask
может потребовать дополнительных пояснений. Наша цель — взять этот процент и превратить его в непрозрачное значение в градациях серого. Мы знаем, что шум Перлина имеет оттенки серого и полностью непрозрачен, поэтому нам нужен порог в том же духе.
Мы берем наше процентное значение и умножаем его на 0xFF
или 255 в десятичном виде. Это максимальное значение для одного канала в наших растровых изображениях. Затем нам нужно поместить это одноканальное значение в каналы R, G и B. В то же время нам нужен 0xFF
в канале А. Для каналов R, G и B мы берем этот channelThreshold и используем операторы смещения битов, чтобы поместить это значение в каждый из каналов. Затем мы складываем их все и получаем наше фактическое пороговое значение.
Это не совсем интуитивно понятно, поэтому давайте попробуем пройти пример.
Если мы установим percent
на .5, при updateMask
сначала будет установлено значение updateMask
0xFF * .5
, что равно 0x7F
.
Используя bitshift operator take the bits that represent that number, and moves them over to the left by the specified number of places. Thus,
0x7F becomes
0x7F00
, and 0x7F becomes
0x7F0000
. It may be confusing as to why bitshifting 8 places only moves the digits by 2 places, but if you know how binary relates to hexadecimal, this will actually make sense. If it doesn't, I'm sorry, but a further explanation would turn this into a tutorial on base numeral systems.bitshift operator take the bits that represent that number, and moves them over to the left by the specified number of places. Thus,
0x7F becomes
0x7F00
, and 0x7F becomes
0x7F0000
. It may be confusing as to why bitshifting 8 places only moves the digits by 2 places, but if you know how binary relates to hexadecimal, this will actually make sense. If it doesn't, I'm sorry, but a further explanation would turn this into a tutorial on base numeral systems.
(Посмотрите эту презентацию Ли Бримелоу, если вы хотите узнать больше о сдвиге битов.)
Независимо от того, сложение 0xFF000000 + 0x7F0000 + 0x7F00 + 0x7F
приводит к 0xFF7F7F7F, который является полностью непрозрачным средне-серым цветом. И затем мы используем это как наш порог, и пиксели, которые темнее, чем те, которые копируются как прозрачный черный, и пиксели, которые светлее, чем те, которые копируются из источника (шум Перлина).
Наконец, проверьте это, перейдя в класс документа ( PerlinTest.as ) и добавив строку для установки percent
:
1
2
3
4
|
public function PerlinTest() {
_mask = new PerlinMask(image_mc);
_mask.percent = .3;
}
|
Вы можете изменить значение на другие значения от 0 до 1 и проверить фильм, чтобы увидеть результаты. Обратите внимание, однако, что один PerlinMask
шума PerlinMask
, процент от .4 может быть менее очевидным, чем PerlinMask
другого PerlinMask
от .3. Это часть случайного характера шума. Вы также можете заметить, что около 0,6 или выше, вы начинаете полностью терять шум; то есть весь источник шума уже находится под порогом. Мы обратимся к этому через мгновение.
Шаг 14: Установка начального процента
Мы должны предположить, что мы хотим получить начальное процентное значение при настройке маски. Мы добавим параметр в конструктор, чтобы указать начальное значение для процента. Все еще в PerlinMask
, измените конструктор, чтобы добавить параметр и установить свойство.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public function PerlinMask(target:DisplayObject, initialPercent:Number=0) {
_target = target;
_rect = new Rectangle(0, 0, _target.width, _target.height);
_maskPixels = new BitmapData(_rect.width, _rect.height, true, 0xFF000000);
_mask = new Bitmap(_maskPixels);
_mask.x = _target.x;
_mask.y = _target.y;
_target.parent.addChild(_mask);
_noise = new BitmapData(_rect.width, _rect.height, false, 0xFFFFFF);
_point = new Point(0, 0);
_blur = new BlurFilter(16, 16, 2);
_operation = «<«;
reseed();
this.percent = initialPercent;
}
|
В строке 21 мы добавляем параметр со значением по умолчанию, равным 0. Затем в последней строке конструктора (строка 39) я удалил вызов updateMask()
и заменил его установкой свойства percent
в значение параметра. Так как updateMask
из установщика percent
, мы можем эффективно заменить его.
Чтобы проверить это, вернитесь на PerlinTest.as и измените код установки:
1
2
3
|
public function PerlinTest() {
_mask = new PerlinMask(image_mc, .3);
}
|
Я удалил вторую строку в конструкторе, который устанавливает процент отдельно, и добавил значение в качестве второго аргумента.
После последнего шага не должно быть никаких реальных изменений в функциональности, но обязательно протестируйте фильм, чтобы убедиться, что вы не ввели ошибки.
Шаг 15: Нормализация порога
Однако есть одна небольшая проблема. Если вы обращали внимание на изображения, создаваемые шумом Перлина, в них много черного, но не очень белого. Некоторые шумовые изображения довольно темные, в то время как другие имеют более высокие значения яркости. Но по какой-то причине они стремятся к более темному концу спектра.
Результатом этого является то, что когда мы устанавливаем процент, скажем, 0,7, у нас уже есть порог, который «утверждает» каждый пиксель, и мы достигаем полностью прозрачную маску немного раньше. Возможно, вы уже заметили это, если вы тестировали различные percent
значения.
Мы можем обойти это, найдя самое высокое значение серого на изображении источника шума Perlin, а затем используя его в качестве значения, из которого мы берем процент, вместо 0xFF
.
Вопрос в том, как найти наибольшее значение серого. Вероятно, существует множество методов для достижения этой цели, но мы будем использовать метод histogram
, предоставленный для объектов BitmapData
с Flash 10.
Это требует немного вычислений, но, к счастью, нам просто нужно сделать это один раз для генерации шума Perlin. Итак, в классе PerlinMask обновите метод reseed()
следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public function reseed():void {
var seed:int = Math.random() * 32000;
_noise.perlinNoise(_rect.width, _rect.height, 2, seed, false, false, 7, true);
var histogram:Vector.<Number> = _noise.histogram()[0];
var i:Number = histogram.length-1;
while (i > 0) {
if (histogram[i] > 0) {
break;
}
i—;
}
_maxGrey = i;
}
|
Вы можете заметить, что последняя строка устанавливает свойство, которое мы еще не определили. Обязательно объявите это с остальными свойствами:
1
2
|
private var _percent:Number;
private var _maxGrey:Number;
|
И, наконец, нам нужно использовать это свойство в updateMask
:
1
2
3
4
5
|
private function updateMask():void {
var channelThreshold:uint = _maxGrey * _percent;
var thresh:uint = 0xFF000000 + (channelThreshold << 16) + (channelThreshold << 8) + channelThreshold;
_maskPixels.threshold(_noise, _rect, _point, _operation, thresh, 0, 0xFFFFFFFF, true);
}
|
Само свойство настраивается и используется обычным способом. Однако логика помещения значения в это свойство может использовать немного больше комментариев.
Метод histogram
принимает один параметр, прямоугольник, определяющий область, для которой необходимо выполнить гистограмму для целевых BitmapData
(в нашем случае это шум Перлина).В нашем коде (строка 46) мы выполняем histogram
на _noise
, не потрудившись даже пройти в Rectangle
потому , что по умолчанию использовать всю область изображения.
Более сложная часть заключается в том, что histogram
возвращается многомерный элемент Vector
Numbers (a Vector
is a Array
, за исключением того, что все элементы в Vector
объявлены как типизированные с определенным типом данных. Он был введен в Flash Player 10, и, по общему мнению, их следует использовать, когда возможно, так как они быстрее, чем Array
с).
Этот возврат Vector
имеет в качестве своих элементов четыре элемента Vector
, каждый из которых представляет один канал. По порядку, они красные, зеленые, синие и альфа (что немного странно, так как в большинстве других стран мы рассматриваем альфу как первый канал. Хотя с этим ничего не поделаешь). Поскольку мы знаем, что наш шум Перлина имеет оттенки серого, мы можем с уверенностью предположить, что красный, зеленый и синий каналы будут одинаковыми. Итак, мы берем первый элемент из Vector
возвращенного histogram
, и в histogram
переменной у нас есть красный канал.
Этот элемент является другим Vector
, и все его элементы Number
s. Есть 256 записей (от 0 до 255). Каждый из этих Number
s представляет значение в этом канале (красный в нашем случае). То есть histogram[0]
представляет красное значение 0x00
и histogram[255]
представляет красное значение 0xFF
. Значения, содержащиеся в этих элементах, представляют собой количество пикселей в том, BitmapData
что имеет это значение красного цвета. Итак, если бы у нас был полностью «черный» красный канал (абсолютно без красного BitmapData
), наш Vector
бы выглядел примерно так:
1
2
3
4
|
histogram[ 0 ] = _noise.width * _noise.height; histogram[ 1 ] = 0 ; //…
histogram[ 255 ] = 0 ; |
Если бы у вас было изображение, где левая половина была заполнена черным, а правая половина — белым, вы получите следующее:
1
2
3
4
5
|
histogram[ 0 ] = _noise.width * _noise.height / 2 ; histogram[ 1 ] = 0 ; //…
histogram[ 254 ] = 0 ; histogram[ 255 ] = _noise.width * _noise.height / 2 ; |
Имейте в виду, что приведенные выше списки кодов являются более иллюстративными; Вы не можете установить гистограмму BitmapData
, установив эти Vector
значения.
Вы видели эти гистограммы в графическом виде, в Photoshop и большинстве других графических редакторов (включая iPhoto):
В этом представлении горизонтальной осью являются значения от 0 до 255 (то есть отдельные слоты в канале Vector
), а вертикальная ось представляет «совокупность» этого значения. Приведенное выше изображение является гистограммой, взятой из образца генерации шума Perlin, и вы можете видеть, что все затягивается к верхнему концу. То есть более высокие значения (более яркие пиксели) имеют меньшее количество населения, таким образом, плоская линия.
Теперь, когда мы знаем, какое возвращаемое значение мы получаем, мы можем работать с ним. Как я только что упомянул, на изображениях шума Перлина не так много яркости. Наш подход заключается в том, чтобы зацикливаться на элементах нашего histogram
Vector
, что является нормальным циклом, за исключением того, что мы начнем с конца и продолжим наш путь назад. На каждой итерации мы проверяем значение, содержащееся в этом слоте, и, если оно больше 0, мы обнаруживаем слот, в котором есть несколько пикселей. Так как мы работаем от верха до низа, первое время, когда это происходит, является наивысшим значением, которое фактически имеет информацию.
Когда у нас есть этот индекс, мы сохраняем его в _maxGrey
свойстве. Это значение будет зависеть от генерируемого шума Перлина, поэтому оно будет несколько произвольным. Но предположим, что это в конечном итоге 0xA4
. Теперь, когда мы запускаем updateMask
, мы используем percent
значение on 0xA4
, а не 0xFF
, и поэтому мы получаем процент между черным и самым ярким пикселем в шуме Перлина. Это динамически генерируемый диапазон, а не просто процент между черным и белым. Нам действительно нужно сделать это только из-за природы шума Перлина, но, надеюсь, вы чему-то научились на этом пути.
Если вам нужно нацелиться на Flash 9, то эта техника не будет работать. Вы можете либо пропустить этот шаг и жить с отключенным процентом, либо самый очевидный подход, который я могу придумать, состоит в том, чтобы по BitmapData
отдельности зациклить пиксели в шуме Перлина , получить их значение и сравнить их вручную, пока не найдете самое высокое значение. Это, безусловно, будет более интенсивным процессом, чем использование histogram
подхода, но я приведу его для совместимости с Flash Player 9 (и Flash Professional CS3). Что-то вроде этого:
1
2
3
4
5
6
7
8
9
|
var w: uint = _noise.width; var h: uint = _noise.height; var maxPixel: uint = 0 ; for ( var j: uint = 0 ; i < h; j++) { for ( var i: uint = 0 ; i < w; i++) { maxPixel = Math.max(maxPixel, _noise.getPixel(i, j)); }
_maxValue = maxPixel >> 16 ; }
|
Я на самом деле не тестировал этот код, так что принимайте его за то, что он стоит.
Шаг 16: Использование Perlin Noise в качестве маски
До сих пор мы делали шум видимым, что удобно, чтобы видеть, что происходит, когда мы развиваемся. Но, в конце концов, мы хотим, чтобы наша _mask
Bitmap
была маской для кого-то другого DisplayObject
. Мы уже настроили target
объект, который в нашем тестовом проекте представляет собой изображение, обернутое в MovieClip
вызываемый объект image_mc
.
Это не займет много, чтобы получить маску. В PerlinMask.as добавьте выделенные строки в конструктор:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public function PerlinMask(target:DisplayObject, initialPercent: Number = 0 ) { _target = target;
_rect = new Rectangle( 0 , 0 , _target.width, _target.height); _maskPixels = new BitmapData(_rect.width, _rect.height, true , 0xFF000000 ); _mask = new Bitmap(_maskPixels); _mask.x = _target.x; _mask.y = _target.y; _target.parent.addChild(_mask); _noise = new BitmapData(_rect.width, _rect.height, false , 0xFFFFFF ); _point = new Point( 0 , 0 ); _blur = new BlurFilter( 16 , 16 , 2 ); _operation = "<=" ; reseed(); this .percent = initialPercent; _target.cacheAsBitmap = true ; _mask.cacheAsBitmap = true ; _target.mask = _mask; }
|
Это так же просто, как установить mask
свойство на _target
. Но мы также должны установить как _mask
и _target
для уже cacheAsBitmap
установлен true
. Когда вы включаете растровое кэширование как для маски, так и для DisplayObject
маскируемой маски, маска учитывает полупрозрачность.
То есть, несмотря на то, что в нашем _mask
растровом изображении есть сплошные сгустки, окруженные прозрачными пикселями, проблема заключается в том, что система маскирования Flash воспринимает растровое изображение как большой прямоугольник. Без кэширования растрового изображения наша маска просто пропустит изображение, поскольку маска представляет собой просто прямоугольник размером с изображение, которое мы маскируем.
Однако включение кэширования растровых изображений позволяет Flash просматривать прозрачность маски и сопоставлять ее с альфа-каналом маскируемого объекта. Это требует немного больше ресурсов процессора, но это то, что нам нужно для нашего эффекта, поэтому мы включаем его.
Чтобы увидеть последствия этого, протестируйте фильм. В зависимости от значения, переданного в initialPercent
in PerlinTest
, вы можете увидеть что-то вроде этого:
Измените числовое значение в коде ниже, чтобы увидеть различные эффекты. 0 означает «без маски», поэтому вы увидите все изображение. 1 означает «полная маска», и вы ничего не увидите. Числа между ними обеспечат пятна изображения.
Шаг 17: Размытие краев
Эффект наступает, но есть еще одна маленькая проблема. В threshold
метод копирует, по существу, один пиксель или другой. Это либо полностью прозрачный, либо полностью непрозрачный. Края к сгусткам псевдоним .
Не только это, но край труден. Эффект был бы немного более трогательным, если бы был мягкий переход между видимой и невидимой частями изображения.
Мы можем решить обе эти проблемы, применив размытие к битовой карте маски. Вот почему мы создали _blur
свойство ранее.
Идея состоит в том, чтобы применить размытие после копирования пикселей из threshold
метода. Это смягчит эти края, избавит от ступенчатого алиасинга и обеспечит градацию между непрозрачным черным и полностью прозрачным. Это так же просто , как с помощью BitmapData
«s applyFilter
метод:
1
2
3
4
5
6
|
private function updateMask(): void { var channelThreshold: uint = _maxGrey * _percent; var thresh: uint = 0xFF000000 + (channelThreshold << 16 ) + (channelThreshold << 8 ) + channelThreshold; _maskPixels.threshold(_noise, _rect, _point, _operation, thresh, 0 , 0xFFFFFFFF , true ); _maskPixels.applyFilter(_maskPixels, _rect, _point, _blur); }
|
Применение фильтра к BitmapData
объектам немного более многословно, но к этому моменту вы будете определять некоторые повторяющиеся темы при работе с BitmapData
методами. Первые параметры — это BitmapData
использование в качестве источника. Интересная возможность состоит в том, что вам не нужно применять фильтр к тому, BitmapData
который фактически отображает фильтр. В нашем случае, однако, мы хотим применить фильтр к нему, _maskPixels
а также отобразить его _maskPixels
, поэтому мы переходим _maskPixels
.
Второй и третий параметры — это то, к Rectangle
чему применяется фильтр, и Point
куда прямоугольник пикселей будет скопирован в BitmapData
. Как обычно (как в нашем приложении, так и в большинстве приложений, связанных с BitmapData
манипуляциями), мы хотим, чтобы весь прямоугольник изображения отображался на (0,0)
. Поэтому мы используем наши хранимые _rect
и _point
объекты.
Последний параметр — это фильтр, который нужно применить. Мы хотим получить такое же количество размытия в маске, поэтому мы создали BlurFilter
объект заранее. Мы можем использовать его каждый раз, когда мы повторно размываем шум, пороговый заново.
Идите и протестируйте фильм снова; вы увидите заметную разницу в способе применения маски.
На этом наш PerlinMask
класс закончен (по крайней мере, для целей этого урока). Наши оставшиеся шаги включают в себя обучение тому, как анимировать маску для классного перехода.
Шаг 18. Загрузите и установите пакет Tweening
Мы будем полагаться на сторонний пакет для управления анимацией. Если у вас уже есть библиотека анимации и вам это удобно, не стесняйтесь ее использовать и пропустите этот шаг. Тем не менее, вам нужно будет выполнить перевод между синтаксисом TweenLite, который вы видите в этом руководстве, и синтаксисом выбранной вами библиотеки анимации.
Перейдите по адресу http://www.greensock.com/tweenlite/, чтобы загрузить версию TweenLite для AS3. Прямая ссылка на почтовый индекс: http://www.greensock.com/as/greensock-as3.zip .
Размер zip-файла составляет около 2 МБ, поэтому при нормальном подключении он должен загружаться довольно быстро. После загрузки распакуйте zip-архив, если ваш браузер не сделает этого автоматически.
В распакованной папке будет файл greensock.swc . Вы можете разместить этот файл в нескольких разных местах.
Самое простое и удобное для наших целей — просто переместить его в папку проекта. Это в значительной степени гарантированно работает, но означает, что вы сможете использовать TweenLite только для этого проекта.
Если у вас настроен глобальный путь к библиотеке, вы можете переместить файл SWC в это место, где он будет доступен для каждого файла Flash, который вы открываете. Если вы хотите его настроить, перейдите в настройки Flash (на Mac: выберите Flash> меню « Настройки» или нажмите Command-U ; на ПК: выберите « Правка»> «Настройки» или нажмите Control-U ). Затем выберите ActionScript из меню слева, затем нажмите кнопку « Настройки ActionScript 3.0…» внизу. Наконец, посередине, где написано « Путь к библиотеке»:нажмите кнопку папки и выберите папку в своей файловой системе, в которую вы поместите глобально доступные SWC. Нажмите OK дважды, чтобы подтвердить ваши предпочтения. И, конечно же, переместите greensock.swc в выбранную вами папку.
Если у вас есть Flash CS3, использовать SWC гораздо сложнее, и обычно проще просто использовать файлы AS вместо SWC. Самое простое, что можно сделать, это просто переместить папку com из загрузки TweenLite в папку вашего проекта.
Шаг 19: Анимация маски
С TweenLite мы можем начать анимировать маску для перехода. Однако следует обратить внимание на одно соображение: мы не собираемся встраивать анимацию в сам PerlinMask
объект. У него есть percent
свойство, которое может использоваться в качестве свойства анимации для любого из доступных пакетов анимации. Требование TweenLite / Max, или Tweener, или GTween, или Twease, или Tweensy, или любой другой сторонней библиотеки потенциально может расходиться с любой другой библиотекой анимации, которая может использоваться. Ответственность PerlinMask
заключается в том, чтобы применить маску и предоставить percent
имущество. Если вы хотите, чтобы это было анимировано, это будет ответственностью другого объекта.
Имея это в виду, откройте PerlinTest
и импортируйте TweenLite
:
1
|
import com.greensock.*;
|
А затем измените конструктор:
1
2
3
4
|
public function PerlinTest() { _mask = new PerlinMask(image_mc, 0 ); TweenLite.to(_mask, 1 , {percent: 1 , delay: 1 }); }
|
Это простая анимация percent
свойства от 0 до 1. Я установил задержку, чтобы у вас был момент, чтобы зарегистрировать экран до того, как маска начала анимироваться, и ни по какой другой причине, на самом деле.
Идите и протестируйте фильм.Вы должны увидеть изображение на короткое время, а затем оно должно раствориться в цвете фона. Если хотите, поменяйте направление с помощью этого кода:
1
2
3
4
|
public function PerlinTest() { _mask = new PerlinMask(image_mc, 1 ); TweenLite.to(_mask, 1 , {percent: 0 , delay: 1 }); }
|
… где мы начинаем маску с 1 и твин до 0, для анимации типа «плавления».
В любом случае, ваш мозг должен более или менее взорваться от удивительного.
Шаг 20: Использование маски с твинами в качестве перехода для слайд-шоу
Для моего последнего трюка я быстро перейду к использованию PerlinMask
класса в качестве основы для слайд-шоу, где изображения сливаются друг с другом.
Для удобства вы можете использовать FLA с именем slideshow.fla, который находится в папке « slideshow-start » пакета загрузки. Если вы хотите начать с нуля, вот что в нем:
- Есть пять изображений. Для простоты в этом примере эти изображения просто импортируются в документ Flash, каждое из которых состоит из символов и размещается на сцене. Этот эффект может быть легко экстраполирован в систему, которая загружает изображения извне, основываясь на данных, загруженных из XML, но это добавляет уровень сложности, который не имеет ничего общего с
PerlinMask
эффектом. - Все пять экземпляров изображения имеют имена, на которые будут ссылаться в классе документа для FLA.
- Все изображения имеют одинаковые размеры и размещены в одном месте.
- Существует файл с именем SlideShow.as , который пуст, но введен как класс документа FLA.
Скопируйте папку com из исходного тестового проекта в новый проект слайд-шоу, чтобы у нас был доступ к PerlinMask
классу.
В классе SlideShow добавьте этот код:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package {
import flash.display.*;
import flash.events.*;
import flash.utils.*;
import com.activetuts.effects.PerlinMask; import com.greensock.*;
import com.greensock.easing.*;
public class SlideShow extends Sprite { private var _images: Array ; private var _masks: Array ; private var _timer:Timer;
private var _index: uint ; public function SlideShow() { _images = [saturn_mc, spiral_mc, mars_mc, hyperion_mc, galacticCenter_mc]; _masks = []; for each ( var img:Sprite in _images) { _masks.push( new PerlinMask(img, 1 )); }
_timer = new Timer( 5000 ); _timer.addEventListener(TimerEvent.TIMER, onTimer); _timer.start();
_index = 0 ; onTimer( null ); }
private function onTimer(e:TimerEvent): void { var mask:PerlinMask = _masks[_index]; var image:Sprite = _images[_index]; setChildIndex(image, this .numChildren- 1 ); mask.reseed(); mask.percent = 1 ; TweenLite.to(mask, 2 , {percent: 0 , ease:Quad.easeOut}); _index++; if (_index >= _masks.length) { _index = 0 ; }
}
}
}
|
После объявлений import и property мы настраиваем все в конструкторе. Сначала мы храним Array
изображения (изображения являются Sprite
объектами, каждое из которых содержит изображение), а также инициализируем пустой массив для хранения масок объектов. Затем мы зацикливаемся на Array
изображениях, и для каждого изображения мы создаем связанную маску. В PerlinMask
ссылается на данное изображение, а также занимает один и тот же слот в _masks
массиве , как изображение делает в _images
массиве.
Следующим шагом является настройка Timer
, которая срабатывает каждые 5 секунд. Вначале мы запускаем прослушиватель таймера вручную, чтобы сразу перейти к первому изображению, вместо того, чтобы ждать 5 секунд до срабатывания таймера. Также есть _index
свойство, которое мы инициализируем равным 0. Это отслеживает положение отображаемого в данный момент изображения в массиве.
Далее, в TIMER
обработчике событий, первое, что мы делаем, это собираем ссылки на текущее изображение и маскируем объекты, используя _index
. Затем мы помещаем изображение в верхнюю часть стека отображения, чтобы оно исчезло поверх предыдущего изображения. Затем мы просим маску, reseed
чтобы мы получили новый переход, удостоверимся, что percent
это 1
так, что изображение начинается полностью невидимым, а затем, наконец, запускаем анимацию percent
движения 0
, приводя изображение в действие.
Последняя часть обработчика события увеличивает _index
свойство, проверяя, находится ли оно в допустимом диапазоне для массива, и переносит его обратно, 0
если это необходимо. Это позволяет нашему слайд-шоу идти бесконечно, возвращаясь к началу.
Продолжая
Есть, конечно, тонкости, которые мы могли бы добавить в PerlinMask
класс. Например, было бы относительно легко добавить некоторые сеттеры и геттеры для степени размытия. Установщик просто установит существующее _blur
свойство blurX
и blurY
желаемое значение. Это может быть даже в дополнение к percent
дополнительному эффекту.
Кроме того, было бы удобно добавить хотя бы метод получения для _target
, чтобы вы всегда могли ссылаться на маскируемый объект из заданной маски. Аналогично, было бы полезно даже добавить установщик для _target
, чтобы вы могли переназначить маску среди любого числа DisplayObject
s. Мы могли бы, например, не создавать пять маскирующих объектов в проекте слайд-шоу; просто создайте его и переназначьте на текущее изображение при необходимости.
Также могут быть выставлены другие параметры, чтобы настроить результат шума Перлина. Октавы, смещения или даже начальное значение потенциально могут быть настроены для конкретных эффектов. Возможно, вы стремитесь к определенному шаблону шума, и вы знаете, что семя 420 дает вам этот шаблон.
Это все полезные идеи, но они выходят за рамки этого урока. Я оставляю это вам в качестве упражнения для реализации этих возможностей, если вы хотите их использовать.
Кредиты изображений
Все изображения, представленные в пакете загрузки и представленные в изображениях и SWF-файлах на этой странице, предоставлены любезно предоставленными НАСА. Они были отобраны из последних постов на сайте Astronomy Picture of the Day, который можно найти здесь . У них есть RSS-канал , который настоятельно рекомендуется.
НАСА предоставляет свои изображения в открытый доступ, как описано здесь . Для полноты изображения были найдены по следующим URL (где вы также можете прочитать о предмете).
- Галактический Центр: http://apod.nasa.gov/apod/ap090614.html
- Гиперион: http://apod.nasa.gov/apod/ap110227.html
- Сатурн и Титан: http://apod.nasa.gov/apod/ap110308.html
- Марс: http://apod.nasa.gov/apod/ap110313.html
- Спиральная Галактика: http://apod.nasa.gov/apod/ap110322.html
Вывод
Нам удалось создать довольно крутой способ перехода рисунка из видимого в нет или наоборот. По пути мы исследовали некоторые из более изощренных методов, связанных с BitmapData
. Я надеюсь, что вы не только расширили свои знания ActionScript, но и получили эффектный эффект для своего набора инструментов. Спасибо, что пришли поиграть!