Добро пожаловать в это введение в работу на уровне пикселей с объектом ActionScript 3 BitmapData. Мы возьмем несколько 2D-изображений, разбим их на составляющие их пиксели, а затем соберем их в виде 3D-изображений, которые мы можем перемещать и вращать.
Окончательный результат предварительного просмотра
Давайте посмотрим на конечный результат, к которому мы будем стремиться:
Шаг 1: настроить
Перед тем, как начать, давайте на минутку посмотрим, как устроен пример проекта. Открыв исходный zip-файл для этого урока, у вас будут источники для каждого значимого шага, вы можете пойти дальше и сделать копию начальной папки, так как это послужит нашей отправной точкой.
Внутри этой папки вы найдете две другие папки; SRC и бен . В папке src мы будем сохранять весь наш код и FLA-файлы, а в папке bin — Flash, где будут сохраняться SWF-файлы. Внутри папки src находятся классы Main.FLA и Main.AS.
Если по какой-либо причине вы обнаружите ошибку в своем коде, попытайтесь ее исправить (всегда полезно учиться на ошибках), но если вы не можете, то не беспокойтесь! Вы можете сразу перейти обратно и использовать одну из папок шагов в исходном zip-файле, ближайшую к тому шагу, на котором вы были.
Шаг 2: Загрузите Away3D
Если вы уже Main.as
файл Main.as
вы уже заметили несколько ссылок на Away3D, 3D-фреймворк для Flash. Нам нужно скачать это и добавить его в наш проект, чтобы продолжить.
Вы можете получить их последнюю версию с сайта Away3D .
После завершения загрузки откройте zip-файл, и внутри папки away3d_3_6_0 \ src вы найдете три папки away3d , nochump и wumedia . Скопируйте их, как показано ниже, в папку src .
Шаг 3: Флэш-файл
Если вы еще этого не сделали, откройте Main.fla
и Main.as
Глядя в библиотеку Flash, вы можете увидеть изображение с именем img1
и MovieClip
с именем экземпляра img1
, которое будет служить основным контейнером для png.
Мы собираемся выполнить быструю компиляцию, чтобы убедиться, что мы правильно добавили Away3D. Если все идет хорошо, мы должны увидеть пустой Flash-фильм с темно-серым фоном и без сообщений об ошибках от Flash.
Шаг 4: Файл Main.as
Main.as
файл Main.as
мы увидим несколько переменных, которые используются в Away3D, на Away3D уже есть множество учебных пособий, но мы быстро повторим их:
1
2
3
4
|
// basic Away3D properties
protected var scene:Scene3D;
protected var camera:TargetCamera3D;
protected var view:View3D;
|
-
Scene3D
— это пространство, которое мы можем использовать для добавления трехмерных объектов, таких как кубы и сферы. -
TargetCamera3D
— это один из многих типов камер, доступных в Away3D, и именно его мы используем, чтобы взглянуть на Scene3D. -
View3D
— это окно просмотра, часто описываемое как «окно», в котором мы видим нашу сцену.
Не вдаваясь в подробности, вы также можете увидеть, что базовая сцена настроена для использования с initAway3d()
. Обратите внимание, что он добавляет ENTER_FRAME EventListener
, это просто говорит Away3D render()
(или рисовать) любые объекты, добавленные в Scene3D
каждый кадр.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
/**
* Away3D basic scene setup
*/
private function initAway3d():void
{
scene = new Scene3D();
camera = new TargetCamera3D({z: -200});
view = new View3D({scene:scene, camera:camera});
addChild(view);
addEventListener(Event.ENTER_FRAME, renderLoop);
}
/**
* the render loop
*/
private function renderLoop(event:Event):void
{
view.render();
}
|
Вот и все для ознакомления с классом Main.as
, мы будем строить все остальное по ходу дела.
Шаг 5: Растровые изображения и BitmapData
Мы собираемся сразу перейти к этим двум классам, так как будем работать с ними на протяжении всего урока. Если вы новичок в Bitmap
и BitmapData
вы можете думать о них как о холсте художников и наборе мазков краски. Это совершенно разные объекты, но оба они связаны, BitmapData содержит всю информацию о пикселях или мазках кисти и ничего бы не нарисовало на холсте или в этом случае, Bitmap!
Давайте проверим это, добавив экземпляр img1 MovieClip
на stage
и сделав его копию, используя Bitmap/BitmapData
.
Изменить Main.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
|
/**
* constructor
*/
public function Main()
{
initAway3d();
drawExample();
}
/**
* a quick example of BitmapData and Bitmap usage
*/
private function drawExample():void
{
// create an instance of the img1 object on the stage to copy
var img:MovieClip = new img1();
addChild(img);
// create a BitmapData object with the following parameters: width, height, transparent, color
var bmpData:BitmapData = new BitmapData(img.width, img.height, true, 0x000000);
// draws a copy of the img MovieClip in to the BitmapData
bmpData.draw(img);
// adds a Bitmap to the stage with the BitmapData (copy of the img1) information to display
var bmp:Bitmap = new Bitmap(bmpData);
bmp.y = img.height;
addChild(bmp);
}
|
Глядя на код drawExample()
, первые две строки просто добавляют объект img1
на stage
, это изображение, которое мы сделаем из копии.
После этого мы создаем объект BitmapData
со следующими параметрами:
-
width
, ширина, чтобы сделатьBitmapData
-
height
, высота, чтобы сделатьBitmapData
-
transparent
, должен лиBitmapData
содержать прозрачные пиксели -
color
, цвет фона
Поскольку мы знаем ширину и высоту из img1
мы установили их напрямую, так как нам понадобится прозрачность, мы устанавливаем следующий параметр в значение true и, наконец, мы указываем 0x000000
или черный в качестве цвета фона, так как он будет выглядеть прозрачным, пока мы не заполним Это.
Шаг 6: растровые изображения и BitmapData продолжение
Продолжая, теперь у нас есть настроенный объект BitmapData
, у нас есть несколько доступных нам опций, мы могли бы, например, перебирать пиксель за пикселем и копировать изображение (мы будем использовать что-то подобное позже в уроке), или мы могли бы используйте метод draw()
.
Метод draw()
принимает MovieClip
или Sprite
в качестве параметра и копирует всю информацию о пикселях из объекта в BitmapData
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
/**
* a quick example of BitmapData and Bitmap usage
*/
private function drawExample():void
{
// create an instance of the img1 object on the stage to copy
var img:MovieClip = new img1();
addChild(img);
// create a BitmapData object with the following parameters: width, height, transparent, color
var bmpData:BitmapData = new BitmapData(img.width, img.height, true, 0x000000);
// draws a copy of the img MovieClip in to the BitmapData
bmpData.draw(img);
// adds a Bitmap to the stage with the BitmapData (copy of the img1) information to display
var bmp:Bitmap = new Bitmap(bmpData);
bmp.y = img.height;
addChild(bmp);
}
|
После этого следующие несколько строк создают объект Bitmap
с информацией о пикселях BitmapData
в качестве параметра, который затем перемещается ниже исходного img MovieClip
и добавляется на stage
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
/**
* a quick example of BitmapData and Bitmap usage
*/
private function drawExample():void
{
// create an instance of the img1 object on the stage to copy
var img:MovieClip = new img1();
addChild(img);
// create a BitmapData object with the following parameters: width, height, transparent, color
var bmpData:BitmapData = new BitmapData(img.width, img.height, true, 0x000000);
// draws a copy of the img MovieClip in to the BitmapData
bmpData.draw(img);
// adds a Bitmap to the stage with the BitmapData (copy of the img1) information to display
var bmp:Bitmap = new Bitmap(bmpData);
bmp.y = img.height;
addChild(bmp);
}
|
При настройке аспекта Bitmap
не требуется много настроек, просто отображается BitmapData, все волшебство заключается в BitmapData
. Теперь при тестировании мы должны получить следующее:
Шаг 7: Чтение информации о пикселях
Теперь у нас есть содержимое внутри объекта BitmapData
вещи начинают становиться интересными, поскольку мы можем начать манипулировать изображениями с помощью getPixel32()
и setPixel32()
.
Начиная с getPixel32()
drawExample()
код drawExample()
сверху на следующее:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/**
* a quick example of BitmapData and Bitmap usage
*/
private function drawExample():void
{
// create an instance of the img1 object on the stage to copy
var img:MovieClip = new img1();
addChild(img);
// create a BitmapData object with the following parameters: width, height, transparent, color
var bmpData:BitmapData = new BitmapData(img.width, img.height, true, 0x000000);
// draws a copy of the img MovieClip in to the BitmapData
bmpData.draw(img);
// adds a Bitmap to the stage with the BitmapData (copy of the img1) information to display
var bmp:Bitmap = new Bitmap(bmpData);
bmp.y = img.height;
addChild(bmp);
// read pixel information from the BitmapData
var pixelInformation:uint = bmpData.getPixel32(5, 0);
trace(pixelInformation, pixelInformation.toString(16));
}
|
Изучив код, мы создали обычную переменную uint и присвоили ей значение пикселя в bmpData
по 5 пикселей по горизонтали и 0 пикселей по вертикали. Помните, что значения начинаются с 0 так:
Зная, что мы решили получить информацию о пикселях для 5,0, это сделало бы его черным пикселем в верхней строке и достаточно уверенным выходным 4278190080 ff000000
Flash: 4278190080 ff000000
setPixel32
это может показаться неправильным, но setPixel32
считывает альфа-значение пикселя (тогда как setPixel
просто читает цвет). Обычно мы работаем с шестнадцатеричными значениями для цветов, таких как FFFFFF
или 000000
поэтому мы можем сказать Flash toString(16)
чтобы получить шестнадцатеричное значение:
Шаг 8: Рисование пикселей
Теперь мы знаем, как считывать информацию о пикселях, рисование пикселей в BitmapData
очень похоже, только на этот раз мы используем setPixel32()
для рисования пикселей в BitmapData, и мы также добавим цикл for
для рисования некоторых пикселей.
Сначала измените код на следующее:
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
|
/**
* a quick example of BitmapData and Bitmap usage
*/
private function drawExample():void
{
// create an instance of the img1 object on the stage to copy
var img:MovieClip = new img1();
addChild(img);
// create a BitmapData object with the following parameters: width, height, transparent, color
var bmpData:BitmapData = new BitmapData(img.width, img.height, true, 0x000000);
// draws a copy of the img MovieClip in to the BitmapData
bmpData.draw(img);
// adds a Bitmap to the stage with the BitmapData (copy of the img1) information to display
var bmp:Bitmap = new Bitmap(bmpData);
bmp.y = img.height;
addChild(bmp);
// read pixel information from the BitmapData
var pixelInformation:uint = bmpData.getPixel32(5, 0);
trace(pixelInformation, pixelInformation.toString(16));
// write pixel information to the BitmapData
var color:uint = 0xffff0000;
var row:uint = 0;
var column:uint = 0;
for(row; row < bmpData.height; row++)
{
bmpData.setPixel32(column, row, color);
column++;
if(column > bmpData.width)
{
column = 0;
}
}
}
|
Новый код начинается с создания обычной переменной uint
именем color
которой мы храним 0xffff0000
: ff полностью прозрачный, ff полностью красный, 00 нет зеленого, 00 нет синего.
Затем создаются два счетчика для строк и столбцов (строки — это линия горизонтальных пикселей, столбцы — это линия вертикальных пикселей). Затем эти счетчики помещаются в цикл for
который каждый раз увеличивает значение строки и счетчика, поэтому при смешивании с setPixel32()
он будет рисовать диагональную линию:
Шаг 9: Класс PixelObject3D
На этом шаге мы собираемся представить класс PixelObject3D.as
. Чтобы сэкономить немного времени, возьмите копию класса из папки Step 8 в исходном zip- Main.fla
и Main.as
ее в папку src
кроме Main.fla
и Main.as
Как только вы это сделаете, давайте взглянем на это, прежде чем мы начнем добавлять код для создания 3D-объектов из пикселей.
1
2
3
4
5
|
// properties
protected var _bitmapData:BitmapData = null;
public var _scaleFactor:Number = 1;
protected var _width:Number = 0;
protected var _height:Number = 0;
|
У нас есть несколько защищенных переменных в верхней части класса, одна для BitmapData
и три Numbers
для ширины, высоты и масштаба объекта.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
/**
* constructor
*/
public function PixelObject3D() {}
/**
* begins the creation process
*/
public function createFromMovieClip(mc:MovieClip):void
{
}
|
За ними следует пустой конструктор класса и метод, с которым мы будем работать, createFromMovieClip()
. Вы заметите, что этот метод принимает параметр типа MovieClip
, так что вы уже можете догадаться, что мы передадим ему MovieClip
и он вернет нам его трехмерное представление. Когда это закончено, то есть!
Шаг 10: экземпляр класса PixelObject3D
Хотя класс PixelObject3D.as
самом деле ничего не делает, давайте добавим его экземпляр в класс Main.as
чтобы мы могли видеть изменения на экране по ходу.
Начиная с добавления приватной переменной:
1
2
3
4
5
6
7
|
// basic Away3D properties
protected var scene:Scene3D;
protected var camera:TargetCamera3D;
protected var view:View3D;
// the Pixel3DObject
protected var po3d:PixelObject3D;
|
После этого добавьте в конструктор вызов createPixelObect3D()
.
1
2
3
4
5
6
7
8
9
|
/**
* constructor
*/
public function Main()
{
initAway3d();
drawExample();
createPixelObect3D();
}
|
Наконец добавьте следующую функцию в файл Main.as
Это создаст экземпляр класса PixelObject3D
, вызовет метод createFromMovieClip()
и передаст ему новый MovieClip
, img1
мы использовали ранее.
Последняя строка, на которую следует обратить внимание: мы добавляем класс PixelObject3D
качестве дочернего элемента сцены, поскольку это 3D-объект, а не Stage
.
01
02
03
04
05
06
07
08
09
10
|
/**
* creates a PixelObject3D
*/
private function createPixelObect3D():void
{
po3d = new PixelObject3D();
po3d.createFromMovieClip(new img1());
scene.addChild(po3d);
}
|
Шаг 11: создать от MovieClip (mc: MovieClip)
Зная, что нам передали MovieClip
мы хотим воссоздать с помощью этого метода, первое, что стоит в нашей повестке дня, — это сделать его копию с использованием BitmapData точно так же, как мы делали раньше. Затем мы можем использовать данные пикселей, чтобы начать создавать трехмерные объекты.
Как и прежде, мы собираемся создать объект BitmapData
и нарисовать объект mc MovieClip
:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
/**
* begins the creation process
*/
public function createFromMovieClip(mc:MovieClip):void
{
// store references and create the bitmapdata
_bitmapData = new BitmapData(mc.width, mc.height, true, 0x000000);
_bitmapData.draw(mc);
// set width / height
_width = mc.width * (2 * _scaleFactor);
_height = mc.height * (2 * _scaleFactor);
}
|
Мы также устанавливаем переменные _width
и _height
соответствии с шириной и высотой mc
и умножаем это на переменную _scaleFactor
, что позволяет нам увеличивать или уменьшать размер трехмерных пикселей, если мы хотим. Подробнее об этом позже.
Шаг 12: создать от MovieClip (mc: MovieClip)
Помните, что BitmapData — это только информация о пикселях, и без добавления BitmapData в растровое изображение мы не сможем его увидеть, но мы все равно можем читать и записывать его. Это идеально для нас, так как мы собираемся использовать этот шаг, чтобы начать цикл по пикселям BitmapData и разделить значения красного, зеленого, синего и альфа.
createFromMovieClip()
ваш createFromMovieClip()
чтобы он соответствовал этому:
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
|
/**
* begins the creation process
*/
public function createFromMovieClip(mc:MovieClip):void
{
// store references and create the bitmapdata
_bitmapData = new BitmapData(mc.width, mc.height, true, 0x000000);
_bitmapData.draw(mc);
// set width / height
_width = mc.width * (2 * _scaleFactor);
_height = mc.height * (2 * _scaleFactor);
// pixel information
var pixelValue:uint = 0;
var red:uint = 0;
var green:uint = 0;
var blue:uint = 0;
var alpha:uint = 0;
// loop through each pixel horizontally
for (var i:int = 0; i < mc.width; i++)
{
pixelValue = _bitmapData.getPixel32(i, 0);
alpha = pixelValue >> 24 & 0xFF;
red = pixelValue >> 16 & 0xFF;
green = pixelValue >> 8 & 0xFF;
blue = pixelValue & 0xFF;
trace(«alpha:» + alpha + » red:» + red + » green:» + green + » blue:» + blue);
}
}
|
Здесь мы установили несколько переменных для значений цвета и альфа, затем запустили цикл for
на основе ширины mc's
.
Этот цикл for
устанавливает переменную pixelValue
в значение текущего пикселя, используя метод getPixel32()
который мы использовали ранее, но на этот раз заметим, что мы использовали 0
для второго параметра, который является y
, поэтому мы собираемся обрабатывать только первая горизонтальная линия пикселей.
После этого есть некоторая довольно сложная математика, известная как битовая маскировка и сдвиг, чтобы сэкономить немного времени, вы можете предположить, что каждый из цветов извлекается из переменной pixelValue
а затем выводить ее для просмотра с помощью trace()
. Если вы хотите больше узнать о побитовых операторах, сдвиговых битах и маскировании, вы можете найти отличный пост на веб-сайте Polygonal Labs .
То, что вы должны увидеть, это вывод целой связки значений 0
но обратите внимание на две строки alpha:255
, это два черных пикселя вверху руки.
Шаг 13: Создание 3D-объектов из значений пикселей
Фу, в этих последних нескольких шагах было довольно много логики! Теперь у нас есть все основы, давайте начнем использовать информацию о пикселях, которую мы получили ранее, чтобы создать 3D-шедевр… почти.
Если вы уже использовали Away3D или Papervision 3D до того, как освоите этот шаг, мы начнем создавать 3D-кубы и применять к ним материалы. Для каждого пикселя, который имеет альфа-значение 255 (непрозрачный), мы берем его цвет и создаем материал на основе цвета для применения к 3D-кубу. Ниже приведен код, который запускает это:
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
|
/**
* begins the creation process
*/
public function createFromMovieClip(mc:MovieClip):void
{
// store references and create the bitmapdata
_bitmapData = new BitmapData(mc.width, mc.height, true, 0x000000);
_bitmapData.draw(mc);
// set width / height
_width = mc.width * (2 * _scaleFactor);
_height = mc.height * (2 * _scaleFactor);
// pixel information
var pixelValue:uint = 0;
var red:uint = 0;
var green:uint = 0;
var blue:uint = 0;
var alpha:uint = 0;
// loop through each pixel horizontally
for (var i:int = 0; i < mc.width; i++)
{
pixelValue = _bitmapData.getPixel32(i, 0);
alpha = pixelValue >> 24 & 0xFF;
red = pixelValue >> 16 & 0xFF;
green = pixelValue >> 8 & 0xFF;
blue = pixelValue & 0xFF;
// if pixel is opaque
if(alpha == 255)
{
// create a regular hex color string ie FFFFFF or 000000
var color:String = red.toString(16) + green.toString(16) + blue.toString(16);
if(color == «000») color = «000000»;
trace(«#» + color);
// create a material from the color and apply to a 3D cube
var material:Material = new ColorMaterial(color);
var cube:Cube = new Cube({material:material, width:2 * _scaleFactor, height:2 * _scaleFactor, depth:2 * _scaleFactor});
// position the cube from a — value so registration/transformation point is always center
cube.x = 0 — (_width/2) + cube.width * i;
this.addChild(cube);
}
}
}
|
В приведенном выше коде мы использовали red
, green
и blue
переменные и создали обычный шестнадцатеричный цвет, который можно увидеть в результате выполнения trace()
.
Затем шестнадцатеричная цветовая переменная color
используется для создания ColorMaterial
с Away3D, который представляет собой обычный материал, основанный на цвете, который можно применять к трехмерным объектам.
После этого мы создаем объект Cube
и указываем material
который будет material
объектом, мы создали линию перед ним. Также стоит отметить, что мы установили width
, height
и depth
(помните, что мы сейчас работаем в трех измерениях!) В значение, в два раза _scaleValue
переменной _scaleValue
, это позволяет нам _scaleValue
кубы путем изменение _scaleValue
.
Наконец, мы помещаем Cube
в ноль минус половину ширины mc
умноженную for
счетчик циклов i
for
i
, это делает точку регистрации или преобразования готового трехмерного объекта в центре. Затем он добавляется как ребенок, и при тестировании вы увидите два маленьких черных 3D- Cube
.
Шаг 14: Строки и столбцы
Теперь два 3D-куба великолепны, и все, но мы действительно хотим, чтобы вся фигура руки была в 3D-кубах. Мы уже используем цикл for
чтобы перебрать все пиксели в первой строке, но как нам получить его, чтобы перебрать оставшиеся строки пикселей?
Вы догадались, еще один цикл!
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
|
/**
* begins the creation process
*/
public function createFromMovieClip(mc:MovieClip):void
{
// store references and create the bitmapdata
_bitmapData = new BitmapData(mc.width, mc.height, true, 0x000000);
_bitmapData.draw(mc);
// set width / height
_width = mc.width * (2 * _scaleFactor);
_height = mc.height * (2 * _scaleFactor);
// pixel information
var pixelValue:uint = 0;
var red:uint = 0;
var green:uint = 0;
var blue:uint = 0;
var alpha:uint = 0;
// loop through each row of pixels
for (var j:int = 0; j < mc.height; j++)
{
// loop through each pixel horizontally
for (var i:int = 0; i < mc.width; i++)
{
pixelValue = _bitmapData.getPixel32(i, j);
alpha = pixelValue >> 24 & 0xFF;
red = pixelValue >> 16 & 0xFF;
green = pixelValue >> 8 & 0xFF;
blue = pixelValue & 0xFF;
// if pixel is opaque
if(alpha == 255)
{
// create a regular hex color string ie FFFFFF or 000000
var color:String = red.toString(16) + green.toString(16) + blue.toString(16);
if(color == «000») color = «000000»;
trace(«#» + color);
// create a material from the color and apply to a 3D cube
var material:Material = new ColorMaterial(color);
var cube:Cube = new Cube({material:material, width:2 * _scaleFactor, height:2 * _scaleFactor, depth:2 * _scaleFactor});
// position the cube from a — value so registration/transformation point is always center
cube.x = 0 — (_width/2) + cube.width * i;
cube.y = (_height/2) + -cube.height * j;
this.addChild(cube);
}
}
}
}
|
На этот раз мы действительно изменили только три вещи, новый цикл for
который на этот раз имеет j
в качестве счетчика. В getPixel32()
теперь добавлена переменная j
в качестве параметра y
и, наконец, Cube
расположен вертикально с помощью счетчика j
.
Это в значительной степени завершает основную логику, теперь она будет проходить по горизонтали, считывать значения пикселей, создавать ColorMaterial
и Cube
и позиционировать их соответственно. Как только он достигает конца горизонтальной линии, из-за нового цикла for
он переходит к следующему пикселю вниз и снова проходит по горизонтали, пока изображение не будет завершено. Посмотрите сами, протестировав фильм:
Шаг 15: в 3-е измерение
Теперь у нас есть все эти 3D объекты, но они выглядят очень 2D, поэтому мы собираемся добавить немного движения и заставить весь объект вращаться.
Для этого нам нужно вернуться к файлу Main.as
и найти метод renderLoop()
. Помните, что Away3D потребуется визуализировать (или рисовать) 3D-изображение в каждом кадре, поэтому мы можем добавить несколько простых вращений в наш PixelObject3D
чтобы увидеть, как вращаются все дочерние Cubes
:
1
2
3
4
5
6
7
8
|
/**
* the render loop
*/
private function renderLoop(event:Event):void
{
pObject3D.rotationZ++;
view.render();
}
|
Не стесняйтесь экспериментировать с rotationX
, rotationY
и rotationZ
здесь, просто не забудьте сбросить его обратно в код выше, прежде чем продолжить. Вы также можете добавить в create3DObject()
чтобы лучше центрировать и выровнять Cubes
по камере.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
/**
* creates a 3D pixel object from a MovieClip
*/
public function create3DObject():void
{
pObject3D = new PixelObject3D();
pObject3D.createFromMovieClip(new img1());
pObject3D.x = 80;
pObject3D.y = -55;
pObject3D.rotationX = -5;
scene.addChild(pObject3D);
}
|
Шаг 16: взрыв PixelObject3D
Теперь это больше похоже на то, что мы можем наконец увидеть вращающийся трехмерный пиксельный объект. Мы можем начать настраивать это и добавить разнесенный вид, просто редактируя значение z
Cubes
при их создании.
Вернитесь к классу PixelObject3d.as
и найдите строки, в которых мы PixelObject3d.as
Cube
x
и y
и добавьте следующее:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
// if pixel is opaque
if(alpha == 255)
{
// create a regular hex color string ie FFFFFF or 000000
var color:String = red.toString(16) + green.toString(16) + blue.toString(16);
if(color == «000») color = «000000»;
trace(«#» + color);
// create a material from the color and apply to a 3D cube
var material:Material = new ColorMaterial(color);
var cube:Cube = new Cube({material:material, width:2 * _scaleFactor, height:2 * _scaleFactor, depth:2 * _scaleFactor});
// position the cube from a — value so registration/transformation point is always center
cube.x = 0 — (_width/2) + cube.width * i;
cube.y = (_height/2) + -cube.height * j;
cube.z = -25 + (Math.random() * 50);
this.addChild(cube);
}
|
Это переместит каждый Cube
на произвольную глубину от -25 до положительной 25 и создаст хороший эффект взрыва:
Шаг 17: Масштабирование
Так как PixelObject3D
немного мал на экране, мы собираемся немного изменить масштаб. Мы можем сделать это быстро, _scaleValue
переменную PixelObject3D.as
классе PixelObject3D.as
и увеличив ее до 1,5.
01
02
03
04
05
06
07
08
09
10
11
12
|
/**
* creates a 3D object from a MovieClip
*
* @author Anton Mills
*/
public class PixelObject3D extends ObjectContainer3D
{
// properties
protected var _bitmapData:BitmapData = null;
public var _scaleFactor:Number = 1.5;
protected var _width:Number = 0;
protected var _height:Number = 0;
|
Шаг 18: Различные изображения
Использовать класс PixelObject3D
для создания других изображений легко, просто импортируйте изображение, которое вы хотите обработать, во Flash. Затем преобразуйте его в мувиклип, как обычно, на этот раз img2
ему имя класса img2
например:
Теперь вы можете изменить Main.as
чтобы использовать новый объект img2
с одним небольшим изменением:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
/**
* creates a 3D pixel object from a MovieClip
*/
public function create3DObject():void
{
pObject3D = new PixelObject3D();
pObject3D.createFromMovieClip(new img2());
pObject3D.x = 80;
pObject3D.y = -55;
pObject3D.rotationX = -5;
scene.addChild(pObject3D);
}
|
Шаг 19: несколько объектов
Вы можете использовать их столько, сколько захотите, просто убедитесь, что вы добавили их в сцену Away3D, и их может быть несколько. В этом примере я удалил свойство z
которое мы использовали в шаге 16 для эффекта взрыва.
Main.as
с другим PixelObject3D
добавил:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
/**
* A tutorial aimed at introducing ActionScript 3’s BitmapData
* and how to use the BitmapData information to create a 3D
* pixel shape using Away3D.
*
* @author Anton Mills
*/
public class Main extends MovieClip
{
// basic Away3D properties
protected var scene:Scene3D;
protected var camera:TargetCamera3D;
protected var view:View3D;
protected var pObject3D:PixelObject3D;
protected var pObject3D2:PixelObject3D;
|
Затем создайте еще один экземпляр:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* creates a 3D pixel object from a MovieClip
*/
public function create3DObject():void
{
pObject3D = new PixelObject3D();
pObject3D.createFromMovieClip(new img2());
pObject3D.x = 40;
pObject3D.y = -55;
pObject3D.rotationX = -5;
scene.addChild(pObject3D);
pObject3D2 = new PixelObject3D();
pObject3D2.createFromMovieClip(new img1());
pObject3D2.x = 115;
pObject3D2.y = -55;
pObject3D2.rotationX = -5;
scene.addChild(pObject3D2);
}
|
И, наконец, поверните его в цикле рендеринга Away3D:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
/**
* the render loop
*/
private function renderLoop(event:Event):void
{
pObject3D.rotationY++;
pObject3D2.rotationY—;
pObject3D2.rotationZ—;
pObject3D2.rotationX++;
view.render();
}
|
Шаг 20: фин.
Осталось только протестировать фильм и насладиться великолепием 2D-пикселей, преобразованных в 3D-объекты. Теперь, что вы можете сделать с BitmapData
в вашем следующем приложении или игре?
Вывод
В этом руководстве мы рассмотрели различные элементы, но в первую очередь сосредоточились на использовании BitmapData
например на рисовании MovieClips
в BitmapData
, используя setPixel32()
для рисования отдельных пикселей, отображения BitmapData
с использованием Bitmap
и чтения значений пикселей с использованием getPixel32()
.
Мы также рассмотрели некоторую цветовую математику, получив шестнадцатеричные цвета и даже отдельные значения альфа, красного, зеленого и синего, используя toString(16)
. Наконец, мы написали небольшой цикл для создания 3D- Cubes
используя значения пикселей, которые мы прочитали, фу!
Существует так много возможностей, когда вы работаете на уровне пикселей, и с небольшим воображением и экспериментированием вы можете создавать действительно классные приложения и игры! Спасибо за ваше время, надеюсь, вам понравился этот урок.