Alternativa 8 для чайников. Часть третья

Материал из AlternativaPlatform Wiki

Перейти к: навигация, поиск

Содержание

[править] Трехмерные объекты

Все трехмерные объекты в Alternativa расширяют класс Object3D. Это и невидимые объекты (Camera3D, Light3D) и вполне реальные (Mesh, Wireframe). Этот класс содержит базовые характеристики трехмерных объектов. Такие свойства как x,y,z,scaleX,scaleY,scaleZ, visible и д.р.

[править] Mesh

Mesh представляет из себя любой полигональный объект. Является базовым классом для классов Box, Decal, GeoSphere, Skin, SkyBox. Описывать его нет смысла. В двух прошлых уроках мы работали по сути только с ним. Просто помните что почти любой полигональный трехмерный объект в Alternativa это Mesh.

[править] Surface

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

Для создания поверхности, используется метод addSurface полигонального объекта.

Параметры метода:

public function addSurface(material:Material, indexBegin:uint, numTriangles:uint):Surface
material:Material — материал поверхности 
indexBegin:uint — Индекс первой вершины начала поверхности среди индексов геометрии.
numTriangles:uint — количество треугольников в поверхности

Посмотрим класс в действии:

box = new Box(200, 200, 200); //создаем box
rootContainer.addChild(box);
 
for (var i:int = 0; i < 6; i++) { //box'у добавляем 6 поверхностей
     var texture:BitmapTextureResource = new BitmapTextureResource(new aLogo[i]().bitmapData); 
     box.addSurface(new TextureMaterial(texture), i*6, 2); //на каждую накладываем свою текстуру
}

Snap31.jpg


[править] SkyBox

Skybox - это обычный по сути куб. Отличие в том, что текстуры натягиваются не на внешние поверхности куба, а на внутренние. Также он не зависит от параметров вьюпорта. На любом удалении камеры от него, его геометрия не будет обрезана. Используется для создания неба. Подробнее о SkyBox можно прочитать здесь: Скайбокс

var textureScyD:BitmapTextureResource = new BitmapTextureResource(new SkyD().bitmapData); //Создаем 6 текстур для нашего ScyBox
var textureScyU:BitmapTextureResource = new BitmapTextureResource(new SkyU().bitmapData);
var textureScyR:BitmapTextureResource = new BitmapTextureResource(new SkyR().bitmapData);
var textureScyL:BitmapTextureResource = new BitmapTextureResource(new SkyL().bitmapData);
var textureScyF:BitmapTextureResource = new BitmapTextureResource(new SkyF().bitmapData);
var textureScyB:BitmapTextureResource = new BitmapTextureResource(new SkyB().bitmapData);
 
skybox = new SkyBox (3000, new TextureMaterial(textureScyL),
                           new TextureMaterial(textureScyR),
                           new TextureMaterial(textureScyB),
                           new TextureMaterial(textureScyF),
                           new TextureMaterial(textureScyD),
                           new TextureMaterial(textureScyU), 
                                                     0.001); //создаем Scybox
rootContainer.addChild(skybox);//Добавляем в контейнер

Расмотрим параметры конструктора:

public function SkyBox(size:Number, left:Material = null, 
                                    right:Material = null, 
                                    back:Material = null, 
                                    front:Material = null, 
                                    bottom:Material = null, 
                                    top:Material = null, 
                                    uvPadding:Number = 0);
size:Number — Размер по всем трём осям. 
left:Material (default = null) — Материал для левой стороны.
right:Material (default = null) — Материал для правой стороны. 
back:Material (default = null) — Материал для задней стороны. 
front:Material (default = null) — Материал для передней стороны. 
bottom:Material (default = null) — Материал для нижней стороны. 
top:Material (default = null) — Материал для верхней стороны. 
uvPadding:Number (default = 0) — Отступ от краёв в текстурных координатах.

Snap32.jpg


[править] WireFrame

WireFrame - класс трехмерных линий. Содержит несколько статических методов для работы с ним. Какой функционал он нам предоставляет:

1) Мы можем любой меш преобразовать в объект состоящий из линий, а не из полигонов.

var parser:ParserA3D = new ParserA3D(); 
    parser.parse(new A3dModel());
    car =  parser.objects[1] as Mesh;
 
    carWireFrame = WireFrame.createEdges(car, 0xFFFFFFFF, 1, 1); //преобразуем меш в трехмерные линии.
    rootContainer.addChild(carWireFrame);//добавляем в контейнер

Параметры метода createEdges():

mesh:Mesh - Меш который будут преобразован в трехмерные линии
color:uint (default = 0) - Цвет линий
alpha:Number (default = 1) - Прозрачность линий
thickness:Number (default = 1) - Толщина линий

Сравните две картинки:

1) Просто Mesh

Snap34.jpg

2) Wireframe

Snap33.jpg

Также у нас есть возможность самим рисовать 3D-линии. Для этого имеются еще 2 статических метода: createLinesList и createLineStrip. В оба из них мы передаем вектор из точек через которые будут рисоваться линии. Отличие в том что метод createLinesList рисует линии попарно между двумя точками, то есть рисуется линия между двумя точками, далее чтобы продолжить рисование с последней точки нужно опять указать ее для следующей линии. А метод createLineStrip рисует непрерывную линию через все точки указанные в векторе.

Испытаем метод createLinesList:

var pointsVector:Vector.<Vector3D> = Vector.<Vector3D>([new Vector3D(  70, -70,  70), new Vector3D(  70,  70,  70), 
                                                        new Vector3D(  70,  70,  70), new Vector3D( -70,  70,  70), 
                                                        new Vector3D( -70,  70,  70), new Vector3D( -70, -70,  70), 
                                                        new Vector3D( -70, -70,  70), new Vector3D(  70, -70,  70),
                                                        new Vector3D(  70, -70, -70), new Vector3D(  70,  70, -70), 
                                                        new Vector3D(  70,  70, -70), new Vector3D( -70,  70, -70),
                                                        new Vector3D( -70,  70, -70), new Vector3D( -70, -70, -70), 
                                                        new Vector3D( -70, -70, -70), new Vector3D(  70, -70, -70),
                                                        new Vector3D(  70, -70,  70), new Vector3D(  70, -70, -70), 
                                                        new Vector3D(  70,  70,  70), new Vector3D(  70,  70, -70), 
                                                        new Vector3D( -70,  70,  70), new Vector3D( -70,  70, -70),
                                                        new Vector3D( -70, -70,  70), new Vector3D( -70, -70, -70)]);
wireFrame = WireFrame.createLinesList(pointsVector, 0xFF00FF00, 1, 3); //передаем вектор точек, цвет, alpha и размер линий
rootContainer.addChild(wireFrame);

Snap35.jpg


[править] Decal

Класс декалей. Декали - это специальные текстуры, которые могут наносится поверх обычных текстур. Например, кровь, следы от пуль, след от гранаты, логотипы и т.п. При этом они обладают устойчивостью к z-файтингу. То есть при любом удалении камеры от них не будет происходить мерцания, из-за того что камера не может понять кто-кого перекрывает.

Вот пример декали крови:

Decal.jpg

Проведем эксперимент.

Создадим вот такой код и скомпилируем его:

package {
	import alternativa.engine3d.controllers.SimpleObjectController;
	import alternativa.engine3d.core.Camera3D;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.Resource;
	import alternativa.engine3d.core.View;
	import alternativa.engine3d.materials.TextureMaterial;
	import alternativa.engine3d.objects.Decal;
	import alternativa.engine3d.primitives.Box;
	import alternativa.engine3d.resources.BitmapTextureResource;
	import flash.display.Sprite;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
 
	/**
	 * ...
	 * @author redefy
	 */
	public class TestDecal extends Sprite {
		[Embed(source="resources/Smoke Kick.png")]
		private static const Smoke:Class;
		[Embed(source="resources/crumple.jpg")]
		private static const Crumple:Class;
		private var rootContainer:Object3D = new Object3D();
 
		private var camera:Camera3D;
		private var stage3D:Stage3D;
		private var simpleController:SimpleObjectController;
 
		private var boxOut:Box;
		private var boxIn:Box;
 
		private var decalOut:Decal;
		private var decalIn:Decal;
 
		public function TestDecal(){
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
 
			camera = new Camera3D(0.1, 200000);
			camera.view = new View(800, 500);
			camera.rotationX = -90 * Math.PI / 180;
			camera.z = 100
			camera.y = -1200;
			addChild(camera.diagram);
			addChild(camera.view);
 
			boxOut = new Box(400, 400, 400);
			var boxOutMaterial:TextureMaterial = new TextureMaterial(new BitmapTextureResource(new Crumple().bitmapData));
			boxOut.addSurface(boxOutMaterial, 12, 2);
			boxOut.x = 400;
			rootContainer.addChild(boxOut);
 
			boxIn = new Box(200, 200, 200);
			var boxInMaterial:TextureMaterial = new TextureMaterial(new BitmapTextureResource(new Smoke().bitmapData));
			boxInMaterial.useDiffuseAlphaChannel = true;
			boxIn.addSurface(boxInMaterial, 12, 2);
			boxIn.x = 400;
			boxIn.y = -101;
			rootContainer.addChild(boxIn);
 
			decalIn = new Decal();
			decalIn.geometry = boxIn.geometry;
			decalIn.addSurface(boxInMaterial, 12, 2);
			decalIn.x = -400;
			decalIn.y = -101;
			rootContainer.addChild(decalIn);
 
			decalOut = new Decal(); 
			decalOut.geometry = boxOut.geometry;
			decalOut.addSurface(boxOutMaterial, 12, 2);
			decalOut.x = -400;
			rootContainer.addChild(decalOut);
 
			rootContainer.addChild(camera);
 
			simpleController = new SimpleObjectController(stage, camera, 400);
 
			stage3D = stage.stage3Ds[0];
			stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
			stage3D.requestContext3D();
		}
 
		private function onContextCreate(e:Event):void {
			for each (var resource:Resource in rootContainer.getResources(true)){
				resource.upload(stage3D.context3D);
			}
			stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
 
		private function onEnterFrame(e:Event):void {
			camera.render(stage3D);
			simpleController.update();
		}
	}
}

При небольшом расстоянии камеры от этих объектов разница не заметна...

Snap36.jpg

Но стоит отодвинуть камеру подальше у объектов box начинается z-файтинг, а у декалей все в порядке.

Snap37.jpg

Для того чтобы избежать z-файтинга и был создан разработчиками этот класс...


[править] Sprite3D

Продолжаем. Sprite3D - это плоский трехмерный объект, который всегда развернут к камере. То есть вы ни про каких условиях не сможете увидеть его обратную сторону.

Давайте создадим и посмотрим его в деле:

var texture:BitmapTextureResource = new BitmapTextureResource(new TextureSprite().bitmapData);
    sprite = new Sprite3D(500, 500, new TextureMaterial(texture)); //создаем спрайт.
    sprite.rotation = 0.8; //поворачиваем
    rootContainer.addChild(sprite);

Как мы можем влиять на его начальные характеристики:

1. Мы можем с помощью свойства rotation установить начальный поворот объекта (в радианах)

2. Так же можем сместить точку привязки sprite3D к камере, делается это с помощью свойств originX и originY. Свойства могут принимать значения от 0 до 1. Значение по умолчанию 0.5 (посередине объекта).

3. Ну и стандартные свойства Object3D --> x,y,z,scaleX и т.д.

Параметры конструктора:

public function Sprite3D(width:Number, height:Number, material:Material = null)
width:Number — Ширина спрайта. 
height:Number — Высота спрайта. 
material:Material (default = null) — Материал.

Snap38.jpg


[править] AxisAlignedSprite

AxisAlignedSprite - Плоский, всегда развёрнутый к камере, ориентированный по оси трёхмерный объект. Мы так же как и у Sprite3D, можем смещать точку привязки, масштабировать его и AxisAlignedSprite также всегда повернут к камере. Чем же AxisAlignedSprite отличается от Sprite3D? Ну давайте разбираться. Во-первых, в отличие от Sprite3D, который мы можем поворачивать только по оси Y, класс AxisAlignedSprite позволяет нам, как это и следует из его названия, указывать поворот по всем трем осям, X || Y || Z. Во-вторых, мы можем выбирать, на что будет обращать AxisAlignedSprite, при выравнивании относительно камеры. Если свойству alignToView установлено значение true (по умолчанию) то спрайт выравнивается относительно поворота камеры по осям, если false то спрайт выравнивается относительно позиции камеры в 3D-пространстве. Я думаю демонстрировать AxisAlignedSprite нет смысла, он выглядит также как и Sprite3D.


[править] AnimSprite

AnimSprite расширяет класс Sprite3D возможностью назначить не один материал, а вектор из материалов. И получить уже не обычный Sprite3D а анимационный спрайт. Посмотрите на картинку:

AnimSprite.png

Из нее мы сделаем анимацию взрыва. Создадим AnimSprite:

var textureMaterial:TextureMaterial;
var phases:BitmapData = new TextureSprite().bitmapData; //Получаем битмапдату картинки
var materials:Vector.<Material> = new Vector.<Material>(); //Создаем вектор материалов
    for (var i:int = 0; i < phases.width; i += 128){ //в цикле режем картинку
	 var bmp:BitmapData = new BitmapData(128, 128, true, 0); //на картинки размером 128x128
	 bmp.copyPixels(phases, new Rectangle(i, 0, 128, 128), new Point());
	 textureMaterial = new TextureMaterial(new BitmapTextureResource(bmp));
	 textureMaterial.useDiffuseAlphaChannel = true;
	 materials.push(textureMaterial); //добавляем в вектор текстуру
    }
 
animSprite = new AnimSprite(128, 128, materials, true); //создаем анимационный спрайт
rootContainer.addChild(animSprite); //добавляем в контейнер
 
............
 
private function onEnterFrame(e:Event):void {
	animSprite.frame++; //чтобы анимация проигрывалась, мы должны менять текущий материал спрайта на следующий
	camera.render(stage3D);
	simpleController.update();
}

Параметры конструктора:

public function AnimSprite(width:Number, height:Number, materials:Vector = null, loop:Boolean = false, frame:int = 0);
width:Number — Ширина спрайта. 
height:Number — Высота спрайта. 
materials:Vector (default = null) — Список материалов. 
loop:Boolean (default = false) — Флаг циклического проигрывания. 
frame:int (default = 0) — Текущий кадр.

Snap39.jpg

Исходники: TestObjectsAlternativa.zip


[править] Источники света

Сначала обсудим общие моменты для всех источников света. Во- первых польза от источников света на сцене будет только если на 3D объекты наложен материал класса VertexLightTextureMaterial или StandartMaterial, так как только они поддерживают динамическое освещение. Все источники света расширяют класс Light3D, который в свою очередь расширяет класс Object3D. Из этого следует что у всех источниках света есть свойства и методы как и у любых других трехмерных объектов (x,y,z,rotationX, scaleY и т.д). Класс Light3D расширяет функционал класса Object3D добавлением двух свойств:color - Цвет источника света и intensity - Интенсивность источника света. Давайте, чтоб я не повторялся просто запомним, что у любого источника света мы можем настроить его цвет и интенсивность. Все источники света расмотрим на примере одной сцены. Начнем...


[править] AmbientLight

Это самый простой источник света. Он освещает все 3D объекты равномерно со всех сторон. То есть без разницы где он будет расположен, объекты и близко находящиеся к нему и далеко от него будут освещены одинаково.

ambientLight = new AmbientLight(0xFFFFFF); //Создаем AmbientLight. Конструктор принимает один аргумент - цвет света
ambientLight.intensity = 0.8; //настраиваем интенсивность света
ambientLight.z = 200;
rootContainer.addChild(ambientLight);

Как вы видите не о каких тенях, затемнениях объектов не может быть и речи.

A1.jpg


[править] DirectionalLight

Направленный источник света. Чтобы задать направление света используйте метод lookAt().

directionalLight = new DirectionalLight(0xC9D231); //Создаем DirectionalLight. Конструктор принимает один аргумент - цвет света
directionalLight.z = 200;
directionalLight.intensity = 4;//настраиваем интенсивность света
rootContainer.addChild(directionalLight); 
....
private function onEnterFrame(e:Event):void {
   directionalLight.lookAt(lion.x, lion.y, lion.z);  //направляем на объект lion (насекомое)
 
   simpleController.update();
   camera.render(stage3D);
}

Что мы имеем. DirectionalLight светит в том направлении в котором мы указали. Те поверхности 3D-объектов которые не попадают в его область действия не будут освещены.

A2.jpg


[править] OmniLight

Точечный источник света с затуханием. Освещение направлено во все стороны равномерно.

omniLight = new OmniLight(0xFF0000, 2000 ,5000); //Создаем OmniLight. 
//Аргументы конструктора OmniLight(color:uint, attenuationBegin:Number, attenuationEnd:Number)
//color:uint - цвет света
//attenuationBegin:Number - радиус начала затухания света
//attenuationEnd:Number - радиус конца затухания света
 
omniLight.intensity = 3; //настраиваем интенсивность света
omniLight.z= - 6500;
rootContainer.addChild(omniLight);

Итак, как мы видим OmniLight освещает круговую область, с радиусом указанным в параметре attenuationEnd (радиус конца затухания света). При этом от своей начальной позиции и до области с радиусом указанным в параметре attenuationBegin(радиус начала затухания света) свет светит равномерно. А потом начинает плавно затухать до области с радиусом attenuationEnd (радиус конца затухания света) и у ее края интенсивность OmniLight будет равной 0.

A3.jpg


[править] SpotLight

Конусный источник света. Это источник света, область освещения которого ограничена конусом. Чтобы задать направление, нужно повернуть источник света или использовать метод lookAt(). Похож на OmniLight, так как также позволяет задать радиус затухания света. Но помимо этого мы также задаем направление света, так что в отличии от OmniLight, SpotLight светит не во все направления от себя, а в какое-то одно.

spotLight = new SpotLight(0xB5DCF5, 0 ,15000, 0.3, 2.0); //Создаем SpotLight. 
//Аргументы конструктора SpotLightt(color:uint, attenuationBegin:Number, attenuationEnd:Number, hotspot:Number, falloff:Number)
//color:uint - цвет света
//attenuationBegin:Number - радиус начала затухания света
//attenuationEnd:Number - радиус конца затухания света
//hotspot:Number — Угол конуса начала затухания света. Задаётся в радианах. 
//falloff:Number — Угол конуса конца затухания света. Задаётся в радианах.
 
spotLight.y = -6000
spotLight.z= - 7500;
spotLight.intensity = 6;  //настраиваем интенсивность света
rootContainer.addChild(spotLight);
....
private function onEnterFrame(e:Event):void {
   spotLight.lookAt(dog.x,dog.y+2000,dog.z);  //направляем на объект dog (робо-пес)
 
   simpleController.update();
   camera.render(stage3D);
}

A4.jpg

Исходники: testScene.rar


[править] События мыши в 3D

Работа с событиями мыши в Alternativa с трехмерными объектами аналогична работе с DisplayObject'ами Flash. Мы так же сначала назначаем слушатель с желаемым типом события, и функцию которая будет выполняться при наступлении этого события. Расмотрим пример. Я создал трехмерную модель земли с тремя 3D-объектами на ней.

D1.jpg

Не бойтесь они не кусаются. Они на самом деле мягкие и пушистые.

D2.jpg

D3.jpg

D4.jpg

Допустим я хочу чтобы по нажатию кнопки мыши на любом из объектов их масштаб увеличивался в двое, а при отпускании мыши уменьшался до обычного. Нет ничего проще. Смотрим код:

package {
 
	import com.greensock.*; //Я использую библиотеку greensock для твининга размеров объекта
	import com.greensock.easing.*;
 
////////////////////////////Классы Alternativa////////////////////////////
	import alternativa.engine3d.controllers.SimpleObjectController;
	import alternativa.engine3d.core.Camera3D;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.Resource;
	import alternativa.engine3d.core.View;
	import alternativa.engine3d.core.events.MouseEvent3D;
	import alternativa.engine3d.lights.AmbientLight;
	import alternativa.engine3d.loaders.ParserA3D;
	import alternativa.engine3d.materials.TextureMaterial;
	import alternativa.engine3d.materials.VertexLightTextureMaterial;
	import alternativa.engine3d.objects.Mesh;
	import alternativa.engine3d.objects.Sprite3D;
	import alternativa.engine3d.primitives.GeoSphere;
	import alternativa.engine3d.resources.BitmapTextureResource;
	import alternativa.engine3d.resources.Geometry;
////////////////////////////Классы Flash////////////////////////////
	import flash.display.Sprite;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
 
	public class Main extends Sprite {
 
		//////////////////////Импорт текстур/////////////////////////////////////
		[Embed(source="resources/textures/boomer.jpg")]     static private const BoomerTexture:Class;
		[Embed(source="resources/textures/hulk_01.jpg")]    static private const HulkTexture:Class;
		[Embed(source="resources/textures/hunter_01.jpg")]  static private const HunterTexture:Class;
		[Embed(source="resources/textures/earth.jpg")]      static private const EarthTexture:Class;
		[Embed(source="resources/textures/background.jpg")] static private const BackTexture:Class;
		///////////////////////Модели//////////////////////////////////////////
		[Embed("resources/models/boomer.a3d",mimeType="application/octet-stream")]  static private const BoomerMesh:Class;
		[Embed("resources/models/hulk.a3d",mimeType="application/octet-stream")]    static private const HulkMesh:Class;
		[Embed("resources/models/hunter.a3d",mimeType="application/octet-stream")]  static private const HunterMesh:Class;
		//////////////////////////////////////////////////////////////////////////
 
		private var rootContainer:Object3D = new Object3D();
		private var camera:Camera3D;
		private var stage3D:Stage3D;
		private var world:Object3D;
		private var simpleController:SimpleObjectController;
 
		private var back:Sprite3D; //Фон
		private var parser:ParserA3D; //парсер
 
		private var earth:GeoSphere; //наша земля
 
		private var boomer:Mesh; //три модельки которые я добавляю на поверхность земли
		private var hulk:Mesh;
		private var hunter:Mesh;
 
		public function Main(){
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
 
			init(); //функция инициализирующая все необходимые параметры
			createMesh(); //функция создающая все объекты-меши
 
			stage3D = stage.stage3Ds[0];
			stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
			stage3D.requestContext3D();
		}
 
		private function init():void {
 
			camera = new Camera3D(0.1, 50000); //тут все уже должно быть понятно без всяких объяснений
			camera.view = new View(1280, 1024); //Нет? Тогда внимательно читаем 2 прошлых урока
			camera.view.antiAlias = 2;
			camera.rotationX = -90 * Math.PI / 180;
			camera.y = -1000;
			camera.z = -100;
			addChild(camera.view);
			addChild(camera.diagram);
			rootContainer.addChild(camera);
 
			world = new Object3D(); //контейнер для всех объектов составляющих землю
			rootContainer.addChild(world);
 
			var backMaterial:BitmapTextureResource = new BitmapTextureResource(new BackTexture().bitmapData);
			back = new Sprite3D(2060, 1430, new TextureMaterial(backMaterial)); //Создаем фон
			back.perspectiveScale = false; //Спрайт не изменяет свой масштаб при удалении <-> приближении камеры
			back.y = 250;
			rootContainer.addChild(back);
 
			var ambientLight:AmbientLight = new AmbientLight(0xFFFFFF); //Фоновый источник света
			ambientLight.intensity = 1;
			ambientLight.z = 200;
			rootContainer.addChild(ambientLight);
 
			simpleController = new SimpleObjectController(stage, world, 150); //контролер для контейнера world
 
			simpleController.unbindKey(37); //сбрасываем действия контроллера
			simpleController.unbindKey(38); //которые назначены на эти клавиши
			simpleController.unbindKey(39); //я отменил управление объектом world
			simpleController.unbindKey(40); //с помощью стрелок
			simpleController.unbindKey(65); //и WASD клавиш
			simpleController.unbindKey(68);
			simpleController.unbindKey(83);
			simpleController.unbindKey(87);
		}
 
		private function createMesh():void { //парсим и добавляем все нужные 3D-объекты на сцену
			var earthMaterial:BitmapTextureResource = new BitmapTextureResource(new EarthTexture().bitmapData);
			earth = new GeoSphere(300, 20); //создаем землю
			earth.setMaterialToAllSurfaces(new VertexLightTextureMaterial(earthMaterial));
			world.addChild(earth);
 
			parser = new ParserA3D(); //создаем парсер
			parser.parse(new BoomerMesh()); //парсим первый 3D объект
			boomer = parser.objects[0] as Mesh; //находим меш
 
			boomer.x = 0; //позиционируем на сцене
			boomer.y = 0;
			boomer.z = 295;
			boomer.scaleX = 2; //и масштабируем до желаемых размеров
			boomer.scaleY = 2;
			boomer.scaleZ = 2;
 
			var boomerTexture:BitmapTextureResource = new BitmapTextureResource(new BoomerTexture().bitmapData);
			boomer.setMaterialToAllSurfaces(new VertexLightTextureMaterial(boomerTexture)); //обтягиваем текстурой
			boomer.addEventListener(MouseEvent3D.MOUSE_DOWN, boomerMouseDown); //слушатель события "клавиша нажата"
			boomer.addEventListener(MouseEvent3D.MOUSE_UP, boomerMouseUp); //слушатель события "клавиша отпущена"
			world.addChild(boomer); //добавляем в контейнер
 
			parser.parse(new HulkMesh()); //остальные объекты парсятся аналогично
			hulk = parser.objects[0] as Mesh;
 
			hulk.x = 345;
			hulk.y = 111;
			hulk.z = 90;
			hulk.rotationX = -90 * Math.PI / 180;
			hulk.rotationY = 180 * Math.PI / 180;
			hulk.rotationZ = -70 * Math.PI / 180;
			hulk.scaleX = 2;
			hulk.scaleY = 2;
			hulk.scaleZ = 2;
 
			var hulkTexture:BitmapTextureResource = new BitmapTextureResource(new HulkTexture().bitmapData);
			hulk.setMaterialToAllSurfaces(new VertexLightTextureMaterial(hulkTexture));
			hulk.addEventListener(MouseEvent3D.MOUSE_DOWN, hulkMouseDown);
			hulk.addEventListener(MouseEvent3D.MOUSE_UP, hulkMouseUp);
			world.addChild(hulk);
 
			parser.parse(new HunterMesh());
			hunter = parser.objects[0] as Mesh;
 
			hunter.x = -198;
			hunter.y = 189;
			hunter.z = -119;
			hunter.rotationX = -70 * Math.PI / 180;
			hunter.rotationY = 180 * Math.PI / 180;
			hunter.rotationZ = 45 * Math.PI / 180;
			hunter.scaleX = 2;
			hunter.scaleY = 2;
			hunter.scaleZ = 2;
 
			var hunterTexture:BitmapTextureResource = new BitmapTextureResource(new HunterTexture().bitmapData);
			hunter.setMaterialToAllSurfaces(new VertexLightTextureMaterial(hunterTexture));
			hunter.addEventListener(MouseEvent3D.MOUSE_DOWN, hunterMouseDown);
			hunter.addEventListener(MouseEvent3D.MOUSE_UP, hunterMouseUp);
			world.addChild(hunter);
 
		}
 
		private function hulkMouseDown(e:MouseEvent3D):void { //при нажатии клавиши на объекте
			TweenLite.to(e.target, 0.7, {scaleX: 3, scaleY: 3, scaleZ: 3, x: 375, ease: Elastic.easeOut}); //увеличиваем его размер
		}
 
		private function hulkMouseUp(e:MouseEvent3D):void { //при отпускании клавиши на объекте
			TweenLite.to(e.target, 0.7, {scaleX: 2, scaleY: 2, scaleZ: 2, x: 345, ease: Elastic.easeOut}); //восстанавливаем  исходный
		}
 
		private function boomerMouseDown(e:MouseEvent3D):void { //аналогично
			TweenLite.to(e.target, 0.7, {scaleX: 3, scaleY: 3, scaleZ: 3, ease: Elastic.easeOut});
		}
 
		private function boomerMouseUp(e:MouseEvent3D):void {
			TweenLite.to(e.target, 0.7, {scaleX: 2, scaleY: 2, scaleZ: 2, ease: Elastic.easeOut});
		}
 
		private function hunterMouseDown(e:MouseEvent3D):void {
			TweenLite.to(e.target, 0.7, {scaleX: 3, scaleY: 3, scaleZ: 3, ease: Elastic.easeOut});
		}
 
		private function hunterMouseUp(e:MouseEvent3D):void {
			TweenLite.to(e.target, 0.7, {scaleX: 2, scaleY: 2, scaleZ: 2, ease: Elastic.easeOut});
		}
 
		private function onContextCreate(e:Event):void { //стандартная операция добавления всех ресурсов в Context3D
			stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
 
			stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			for each (var resource:Resource in rootContainer.getResources(true)){
				resource.upload(stage3D.context3D);
			}
		}
 
		private function onEnterFrame(e:Event):void {
			simpleController.update();
			camera.render(stage3D);
		}
	}
}

Попробуйте нажать на любой из трех объектов. Вы получите примерно это:

D5.jpg

Конечно, мы также могли бы сделать переход на какую-нибудь web-страничку по клику на них, и любое другое действие.

Перечислю все типы событий которые мы можем слушать:

CLICK 
DOUBLE_CLICK
MOUSE_DOWN
MOUSE_MOVE
MOUSE_OUT
MOUSE_OVER
MOUSE_UP 
MOUSE_WHEEL
ROLL_OUT
ROLL_OVER

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

Исходник: Earth.zip


Автор #redefy

Использована информация с официальной документации по Alternativa3D 8

Все вопросы по уроку задавать на форум DEMIART.RU

Личные инструменты
Пространства имён
Варианты
Действия
Навигация
Category
Инструменты
На других языках