Статьи

Путешествие в следующее измерение с Papervision3D: Часть 1

В связи с нашей бесплатной раздачей Papervision3D Essentials , сегодняшний урок также содержит тему PV3D.

Этот учебник, состоящий из двух частей, покажет вам, как начать работу с движком Papervision3D, а затем, как заставить ваше творение выпрыгнуть из экрана, используя эффект анаглифа в сочетании с 3D-очками.




Есть пара 3D-очков валяется? Здесь, в Великобритании, на Канале 4 проходит специальная 3D-неделя — семь дней телевизионных программ, транслируемых в 3D — так делают многие люди. Давайте использовать их.

Этот учебник, состоящий из двух частей, покажет вам, как начать работу с движком Papervision3D , а затем, как заставить свое творение выпрыгнуть из экрана.

В этой первой части вы изучите основы PV3D, и в итоге получите что-то вроде этого:

Куб из кубиков

… а во второй части вы узнаете об эффекте анаглифа для 3D-очков и примените его к тому, что вы сделали следующим образом:

В трех славных де

Если вы используете Flash, создайте новый файл ActionScript 3.0 Flash. Установите размер сцены так, как вам нравится — я буду придерживаться значения по умолчанию 550 на 400 пикселей.

Пока вы это делаете, создайте новый файл ActionScript и сохраните его как Main.as в той же папке, что и ваш FLA. Мы собираемся использовать этот файл AS в качестве класса документа FLA, поэтому щелкните пустое место в вашем FLA-файле и введите Main в поле «Класс документа» на панели «Свойства».

Класс документа

(Если вы не используете Flash IDE, просто создайте новый проект AS3.)

Перейдите на страницу загрузки Papervision . Существует множество разных версий и несколько разных типов файлов (zip, swc, mxp). Просто возьмите последнюю версию .zip-файла (там должно быть указано « Рекомендуемые рядом с ним»). Тот, который я использую, называется Papervision3D 2.1.920.zip (для использования с книгой «Papervision3D Essentials») .

Извлеките ZIP-файл, который вы только что загрузили, в любое место на вашем жестком диске. Мне нравится хранить все разные движки, которые я использую, в одной папке, но решать вам.

Flash должен знать, где вы извлекли Papervision, прежде чем он сможет его использовать. Для этого мы используем путь к классам : нажмите « Правка»> «Настройки» , выберите « ActionScript» , затем нажмите « Настройки ActionScript 3.0 …» .

В появившемся окне щелкните маленький значок «перекрестие», найдите папку, в которую вы распаковали Papervision, и нажмите «ОК». Нажимайте OK на другие поля, пока не вернетесь к FLA.

Classpath

Если вы не используете Flash IDE, вам придется установить это по-другому. Например, в FlashDevelop вы должны нажать « Инструменты»> «Глобальные пути к классам» .

В Papervision все ваши трехмерные объекты должны быть размещены внутри сцены . Это как этап в обычном ActionScript. Итак, прежде чем что-то делать, нам нужно создать объект Scene3D, который будет содержать все остальное.

Переключитесь на файл Main.as. Давайте быстро добавим базовый код, необходимый для любого класса документа:

01
02
03
04
05
06
07
08
09
10
11
12
package
{
    import flash.display.MovieClip;
     
    public class Main extends MovieClip
    {
        public function Main()
        {
             
        }
    }
}

Объект Scene3D находится в org.papervision3d.scenes.Scene3D , поэтому нам нужно импортировать его , затем создать новый публичный var для хранения сцены и, наконец, создать реальный объект сцены: (строки 4, 8 и 12)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package
{
    import flash.display.MovieClip;
    import org.papervision3d.scenes.Scene3D;
     
    public class Main extends MovieClip
    {
        public var scene:Scene3D;
         
        public function Main()
        {
            scene = new Scene3D();
        }
    }
}

Для начала давайте создадим большой простой куб, сидящий на нашей сцене.

Мы сделаем те же шаги, что и выше, чтобы создать его, а затем добавим его в нашу сцену: (строки 5, 10, 15, 16)

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package
{
    import flash.display.MovieClip;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.objects.primitives.Cube;
     
    public class Main extends MovieClip
    {
        public var scene:Scene3D;
        public var cube:Cube;
         
        public function Main()
        {
            scene = new Scene3D();
            cube = new Cube();
            scene.addChild( cube );
        }
    }
}

Обратите внимание, что мы используем addChild (), чтобы добавить куб в сцену, так же, как мы добавляем мувиклип в рабочую область.

Приведенный выше код выдаст вам ошибку, если вы попытаетесь запустить его. Это потому, что мы не сказали кубу, как должны выглядеть его поверхности.

Papervision использует материалы, чтобы описать, как выглядит поверхность. Мы можем сделать очень простой, однотонный материал, используя ColorMaterial :

1
var grayMaterial:ColorMaterial = new ColorMaterial( 0xCCCCCC );

«0xCCCCCC» представляет серый цвет; просто возьмите код цвета любого цвета и замените # на 0x :

цветовой код для серого

Поскольку куб имеет шесть граней, нам нужно дать ему шесть материалов. Для этого мы помещаем все шесть в список:

1
2
3
4
5
6
7
var materialsList:MaterialsList = new MaterialsList();
materialsList.addMaterial( grayMaterial, «front» );
materialsList.addMaterial( grayMaterial, «back» );
materialsList.addMaterial( grayMaterial, «left» );
materialsList.addMaterial( grayMaterial, «right» );
materialsList.addMaterial( grayMaterial, «top» );
materialsList.addMaterial( grayMaterial, «bottom» );

… и затем передаем этот список кубу при его создании:

1
cube = new Cube( materialsList );

Таким образом, весь ваш код должен выглядеть примерно так: (не забудьте про операторы импорта !)

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
package
{
    import flash.display.MovieClip;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.materials.ColorMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
     
    public class Main extends MovieClip
    {
        public var scene:Scene3D;
        public var cube:Cube;
         
        public function Main()
        {
            var grayMaterial:ColorMaterial = new ColorMaterial( 0xCCCCCC );
            var materialsList:MaterialsList = new MaterialsList();
            materialsList.addMaterial( grayMaterial, «front» );
            materialsList.addMaterial( grayMaterial, «back» );
            materialsList.addMaterial( grayMaterial, «left» );
            materialsList.addMaterial( grayMaterial, «right» );
            materialsList.addMaterial( grayMaterial, «top» );
            materialsList.addMaterial( grayMaterial, «bottom» );
             
            scene = new Scene3D();
            cube = new Cube( materialsList );
            scene.addChild( cube );
        }
    }
}

Итак, у нас нет ошибок, но чтобы что-то увидеть, нам нужно добавить камеру на сцену. Мы увидим все через «объектив» камеры.

Добавление камеры так же просто, как добавление куба — на самом деле проще, поскольку нам не нужно добавлятьChild () в сцену:

1
import org.papervision3d.cameras.Camera3D;
1
public var camera:Camera3D;
1
2
3
4
scene = new Scene3D();
cube = new Cube( materialsList );
scene.addChild( cube );
camera = new Camera3D();

Теперь на сцене есть камера, но она не подключена ни к какому выходу, поэтому мы все еще не можем видеть куб!

По умолчанию куб помещается прямо в центр сцены (при x = 0, y = 0, z = 0), а камера располагается на расстоянии 1000 единиц от него (при x = 0, y = 0, г = -1000).

Как мы можем получить изображение, которое камера видит в окне Flash Player?

Как привязать камеру к сцене?

Ответ: мы используем окно просмотра . Это тип DisplayObject, например, MovieClip, поэтому мы можем добавитьChild () к сцене. Но мы также можем заставить Papervision визуализировать (т. Е. Нарисовать) изображение с камеры в этом окне просмотра — это немного похоже на то, как художник рисует то, что он может видеть через объектив камеры, затем берет свой рисунок и прикрепляет его к телевизору. Кроме быстрее.

Итак, нам нужно создать окно просмотра и рендер:

1
2
import org.papervision3d.view.Viewport3D;
import org.papervision3d.render.BasicRenderEngine;
1
2
public var viewport:Viewport3D;
public var renderer:BasicRenderEngine;
1
2
3
4
5
//put this at the end of Main()
viewport = new Viewport3D();
viewport.autoScaleToStage = true;
addChild( viewport );
renderer = new BasicRenderEngine();

Теперь все, что нам нужно сделать, это заставить рендерер выполнить фактический рендеринг. Для этого ему нужно знать сцену, камеру и область просмотра:

1
renderer.renderScene( scene, camera, viewport );

В конце концов! Мы можем наконец проверить SWF. Барабанная дробь, пожалуйста …

Невероятный серый квадрат, дамы и господа

Невероятно! Изумительно! Хорошо, хорошо, это на самом деле довольно отстойно. Как мы можем даже сказать, что это куб? Это похоже на квадрат.

Если мы повернем куб, мы сможем определить, действительно ли это куб или нет.

Поскольку куб находится в трех измерениях, слово «вращать» немного сбивает с толку — какое направление мы имеем в виду? Нам нужно указать, вращаемся ли мы вокруг оси x, оси y или оси z.

У объекта Cube есть три свойства, которые мы можем использовать для определения этого, которые называются (неудивительно) вращение X, вращение Y и вращение Z. Давайте изменим пару из них:

1
2
3
4
5
6
scene = new Scene3D();
cube = new Cube( materialsList );
cube.rotationX = 25;
cube.rotationY = 40;
scene.addChild( cube );
camera = new Camera3D();
Невероятный серый КУБ, дамы и господа

Это лучше, но поскольку все лица одного цвета, они просто сливаются друг с другом. Давайте это исправим.

Вместо серого я буду рисовать по бокам логотип ActiveTuts + .

Если вы используете Flash IDE, создайте новый фрагмент ролика и нарисуйте или вставьте изображение, которое хотите использовать. Я включил логотип в библиотеку моего FLA внутри почтового индекса.

Щелкните правой кнопкой мыши свой видеоклип и выберите «Свойства». Проверьте «экспорт для ActionScript» и присвойте ему имя класса. Это позволит вам получить доступ к нему с помощью кода. (Если вы не используете Flash IDE, zip также содержит SWC с MovieClip с именем ActiveTutsLogo, который вы можете использовать. Или вы можете создать новый MovieClip в коде и добавить свое изображение в него. Я не собираюсь вдавайтесь в детали этого здесь, хотя.)

Вместо ColorMaterial мы будем использовать MovieMaterial , и вместо указания цвета мы будем указывать фрагмент ролика. Так что замените это:

1
2
3
4
5
6
7
8
var grayMaterial:ColorMaterial = new ColorMaterial( 0xCCCCCC );
var materialsList:MaterialsList = new MaterialsList();
materialsList.addMaterial( grayMaterial, «front» );
materialsList.addMaterial( grayMaterial, «back» );
materialsList.addMaterial( grayMaterial, «left» );
materialsList.addMaterial( grayMaterial, «right» );
materialsList.addMaterial( grayMaterial, «top» );
materialsList.addMaterial( grayMaterial, «bottom» );

…с этим:

1
2
3
4
5
6
7
8
9
var logoMaterial:MovieMaterial = new MovieMaterial( new ActiveTutsLogo() );
//replace «ActiveTutsLogo» above with the Class name of your movie clip
var materialsList:MaterialsList = new MaterialsList();
materialsList.addMaterial( logoMaterial, «front» );
materialsList.addMaterial( logoMaterial, «back» );
materialsList.addMaterial( logoMaterial, «left» );
materialsList.addMaterial( logoMaterial, «right» );
materialsList.addMaterial( logoMaterial, «top» );
materialsList.addMaterial( logoMaterial, «bottom» );

Вам также необходимо импортировать MovieMaterial:

1
import org.papervision3d.materials.MovieMaterial;

Проверьте это снова:

Помятый куб

Ну, это работает, но выглядит немного помятым.

«Помятый» вид объясняется тем, что Papervision по умолчанию настроен на быстрое, а не точное рисование. Я хочу убедиться, что это руководство будет работать на более медленных компьютерах, поэтому я собираюсь на этом остановиться, но вот как вы можете улучшить его:

Когда вы создаете куб, вы можете передать ему параметры, чтобы определить, на сколько сегментов делится каждая грань. Чем больше сегментов вы выберете, тем точнее будет выглядеть куб, но тем медленнее он будет отображаться.

Я обнаружил, что 10 — это хорошее количество сегментов для использования в каждом направлении. Вот как выглядит код для этого:

1
cube = new Cube( materialsList, 500, 500, 500, 10, 10, 10 );

Пятый, шестой и седьмой параметры определяют количество сегментов, используемых в каждом направлении. Однако, чтобы установить их, мы должны указать все параметры и до пятого.

Мы уже указываем первый параметр — это список материалов. Второй, третий и четвертый параметры определяют ширину, глубину и высоту куба. По умолчанию они установлены на 500, поэтому я сохранил их здесь.

Если вы используете вышеуказанную строку кода, ваш куб будет выглядеть так:

Умный куб

Намного аккуратнее!

Мы можем вращать обычный MovieClip, увеличивая его свойство вращения в каждом кадре — и, конечно, мы можем делать то же самое с кубом и его значениями вращения X / Y / Z

Создайте прослушиватель событий ENTER_FRAME, который будет запускать каждый кадр:

1
import flash.events.Event;
1
2
//at the bottom of Main()
addEventListener( Event.ENTER_FRAME, onEnterFrame );
1
2
3
4
5
6
7
//as a new function
//inside the Main class but outside the Main() function
public function onEnterFrame( evt:Event ):void
{
    cube.rotationX = cube.rotationX + 5;
    cube.rotationY = cube.rotationY + 5;
}

Это заставит куб поворачиваться чуть больше с каждым кадром. Так что если вы сейчас протестируете SWF … куб останется полностью неподвижным. А?

Вспомните художника. Мы все еще смотрим на его старую фотографию — нам нужно, чтобы он рисовал нам новую каждый кадр, иначе мы не увидим никаких изменений!

Итак, измените функцию onEnterFrame ():

1
2
3
4
5
6
public function onEnterFrame( evt:Event ):void
{
    cube.rotationX = cube.rotationX + 5;
    cube.rotationY = cube.rotationY + 5;
    renderer.renderScene( scene, camera, viewport );
}

Проверьте это сейчас:

Один кубик хорош, но поскольку Роман уже показал вам, как это сделать с Away3D , давайте пойдем дальше.

Давайте добавим еще несколько, чтобы сформировать горизонтальную линию кубов. Для этого мы можем использовать простой цикл for ; просто замените этот код:

1
2
3
4
cube = new Cube( materialsList );
cube.rotationX = 25;
cube.rotationY = 40;
scene.addChild( cube );

…с этим:

1
2
3
4
5
6
for ( var i:int = -1; i <= 1; i++ )
{
    cube = new Cube( materialsList );
    cube.x = i * 350;
    cube.rotationX = 25;
}

Обратите внимание, что я делаю положение x каждого куба в зависимости от того, как далеко мы пройдем через цикл. Если вы запустите это, вы получите следующее:

странный

Упс, кубики слишком близко друг к другу. Мы можем уменьшить их, чтобы обойти это; просто измените свойство масштаба каждого куба:

1
2
3
4
5
6
7
8
9
for ( var i:int = -1; i <= 1; i++ )
{
    cube = new Cube( materialsList );
    cube.x = i * 350;
    cube.scale = 0.40;
    cube.rotationX = 25;
    cube.rotationY = 40;
    scene.addChild( cube );
}
Один странный куб

Так что это решает проблему пересечения, но вращается только один из наших кубов. Как придешь?

Это потому, что переменная куба всегда ссылается только на последний созданный куб — и наша функция onEnterFrame () изменяет только вращения этого одного куба.

Итак, чтобы это исправить, нам понадобится массив . Так же, как в нашем списке материалов хранится несколько материалов, наш массив будет хранить несколько кубов.

1
public var cubeArray:Array;
01
02
03
04
05
06
07
08
09
10
11
cubeArray = new Array();
for ( var i:int = -1; i <= 1; i++ )
{
    cube = new Cube( materialsList );
    cube.x = i * 350;
    cube.scale = 0.40;
    cube.rotationX = 25;
    cube.rotationY = 40;
    scene.addChild( cube );
    cubeArray.push( cube );
}

(«Push» означает «добавить в конец списка».)

Теперь, когда каждый куб находится в массиве, мы можем пройти через массив каждый кадр и повернуть каждый из них:

1
2
3
4
5
6
7
8
9
public function onEnterFrame( evt:Event ):void
{
    for each ( cube in cubeArray )
    {
        cube.rotationX = cube.rotationX + 5;
        cube.rotationY = cube.rotationY + 5;
    }
    renderer.renderScene( scene, camera, viewport );
}

Цикл «для каждого» заставляет переменную куба обращаться по очереди к каждому кубу, а не только к последнему кубу, созданному, как это было раньше. Вот результат:

Три кубика подряд

Успех!

Мы сделали ряд кубиков, поэтому квадрат не будет сложным. Вместо того, чтобы просто сделать три куба, мы сделаем три линии из трех кубов.

Для этого мы можем использовать цикл внутри цикла, например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
for ( var i:int = -1; i <= 1; i++ )
{
    for ( var j:int = -1; j <= 1; j++ ) //loop inside a loop
    {
        cube = new Cube( materialsList );
        cube.x = i * 350;
        cube.y = j * 350;
        cube.scale = 0.40;
        cube.rotationX = 25;
        cube.rotationY = 40;
        scene.addChild( cube );
        cubeArray.push( cube );
    } //don’t forget this closing bracket either
}

Проверьте это:

Квадрат кубов

Ницца. И обратите внимание, что нам вообще не нужно было менять код внутри onEnterFrame (); цикл, который запускает каждый кадр, просто вращает каждый куб в массиве — и мы по-прежнему помещаем каждый куб в массив.

Ну, было бы неутешительно останавливаться на площади, не так ли? В конце концов, это 3D-учебник.

Я ожидаю, что вы можете выяснить, как сделать этот шаг самостоятельно. Но если вы хотите сравнить:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
for ( var i:int = -1; i <= 1; i++ )
{
    for ( var j:int = -1; j <= 1; j++ )
    {
        for ( var k:int = 0; k <= 2; k++ )
        {
            cube = new Cube( materialsList );
            cube.x = i * 350;
            cube.y = j * 350;
            cube.z = k * 350;
            cube.scale = 0.40;
            cube.rotationX = 25;
            cube.rotationY = 40;
            scene.addChild( cube );
            cubeArray.push( cube );
        }
    }
}

Я был немного подлый здесь. Я начал k с 0 вместо -1, потому что в противном случае самый передний слой кубов был бы слишком близко к камере. Конечно, вы можете использовать любые цифры, которые вам нравятся.

Эй, вы заметили, что «помятый» эффект практически исчез, когда мы используем кубики меньшего размера?

Куб из кубиков

Потрясающие!

Это всего лишь царапина на поверхности того, что вы можете сделать с Papervision3D. Прежде чем перейти к 3D-очкам, вот несколько вещей, с которыми вы можете поэкспериментировать:

  • Перемещение кубов вместо их вращения: вы можете просто изменить свойства x, y и z каждого куба.
  • Замена кубов сферами: если вы импортируете org.papervision3d.objects.primitives.Sphere, вы можете использовать класс Sphere. Проверьте документы по этому вопросу здесь .
  • Управление камерой с помощью мыши: вы можете получить координаты мыши по осям X и Y в любое время с помощью свойств mouseX и mouseY . Вы можете перемещать камеру, изменяя ее свойства x, y и z. Почему бы не связать их вместе?

Во второй части вы узнаете, как заставить вашу сцену работать с 3D-очками. Так что, если у вас есть пара, не выбрасывайте их!

А пока спасибо за чтение первой части. Я надеюсь, что вы сочли полезным. Если у вас есть какие-либо вопросы, или если что-то сбивает с толку, пожалуйста, оставьте комментарий ниже.