现在的位置: 首页 > 综合 > 正文

Alternativa 3D Series – Tutorial 1 – Getting Started

2013年01月24日 ⁄ 综合 ⁄ 共 7624字 ⁄ 字号 评论关闭

Alternativa 是基于flash的3d引擎。使用Alternativa我们可以直接在web页面嵌入3d应用。在链接互联网的pc上,flashplayer的安装率超过了90%。因此使用alternative3d制作的应用,不必考虑麻烦用户安装多余的插件。在接下来的一系列文章中,我将向你展示如何使用alternative3d和flex制作简单的3D应用。

  

本系列教程内容虽然不是“Hello world”,但是他同样很简单。在文章开始部分,我们会着手制作一个后续文章方便扩展的框架。本着这个目标,我们首先会将逻辑关系和引擎的管理部分进行分离。逻辑管理部分仅用来描述程序自身的一些特性。

代码

1 package
2 {
3 import flash.display.StageAlign;
4 import flash.display.StageScaleMode;
5 import flash.events.Event;
6 import mx.collections.ArrayCollection;
7 import mx.core.Application;
8 import mx.core.UIComponent;
9 import alternativa.engine3d.controllers.CameraController;
10 import alternativa.engine3d.core.Camera3D;
11 import alternativa.engine3d.core.Object3D;
12 import alternativa.engine3d.core.Scene3D;
13 import alternativa.engine3d.display.View;
14 import alternativa.utils.FPS;
15
16 /**
17 * The EngineManager holds all of the code related to maintaining the Alternativa 3D engine.
18 */
19 public class EngineManager extends UIComponent
20 {
21 public var scene:Scene3D;
22 public var view:View;
23 public var camera:Camera3D;
24 public var cameraController:CameraController;
25
26 // a collection of the BaseObjects
27   protected var baseObjects:ArrayCollection = new ArrayCollection();
28 // a collection where new BaseObjects are placed, to avoid adding items
29 // to baseObjects while in the baseObjects collection while it is in a loop
30   protected var newBaseObjects:ArrayCollection = new ArrayCollection();
31 // a collection where removed BaseObjects are placed, to avoid removing items
32 // to baseObjects while in the baseObjects collection while it is in a loop
33 protected var removedBaseObjects:ArrayCollection = new ArrayCollection();
34 // the last frame time
35 protected var lastFrame:Date;
36
37 public function EngineManager()
38 {
39 super();
40 addEventListener(Event.ADDED_TO_STAGE, init);
41 }
42
43 public function init(e:Event): void
44 {
45 stage.scaleMode = StageScaleMode.NO_SCALE;
46 stage.align = StageAlign.TOP_LEFT;
47
48 // Creating scene
49 scene = new Scene3D();
50 scene.root = new Object3D();
51
52 // Adding camera and view
53 camera = new Camera3D();
54 camera.x = 100;
55 camera.y = -150;
56 camera.z = 100;
57 scene.root.addChild(camera);
58
59 view = new View();
60 addChild(view);
61 view.camera = camera;
62
63 // Connecting camera controller
64 cameraController = new CameraController(stage);
65 cameraController.camera = camera;
66 cameraController.setDefaultBindings();
67 cameraController.checkCollisions = true;
68 cameraController.collisionRadius = 20;
69 cameraController.controlsEnabled = true;
70
71 // FPS display launch
72 FPS.init(stage);
73
74 stage.addEventListener(Event.RESIZE, onResize);
75 stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
76 onResize(null);
77
78 // set the initial frame time
79 lastFrame = new Date();
80
81 // start the application
82 ApplicationManager.Instance.startupApplicationManager();
83 }
84
85 private function onResize(e:Event):void
86 {
87 view.width = stage.stageWidth;
88 view.height = stage.stageHeight;
89 Application.application.width = stage.stageWidth;
90 Application.application.height = stage.stageHeight;
91 }
92
93 protected function onEnterFrame(event:Event):void
94 {
95 // Calculate the time since the last frame
96 var thisFrame:Date = new Date();
97 var seconds:Number = (thisFrame.getTime() - lastFrame.getTime())/1000.0;
98 lastFrame = thisFrame;
99
100 // sync the baseObjects collection with any BaseObjects created or removed during the
101 // render loop
102 removeDeletedBaseObjects();
103 insertNewBaseObjects();
104
105 // allow each BaseObject to update itself
106 for each (var baseObject:BaseObject in baseObjects)
107 baseObject.enterFrame(seconds);
108
109 // User input processing
110 cameraController.processInput();
111 // Scene calculating
112 scene.calculate();
113 }
114
115 public function addBaseObject(baseObject:BaseObject):void
116 {
117 newBaseObjects.addItem(baseObject);
118 }
119
120 public function removeBaseObject(baseObject:BaseObject):void
121 {
122 removedBaseObjects.addItem(baseObject);
123 }
124
125 protected function shutdownAll():void
126 {
127 // don't dispose objects twice
128 for each (var baseObject:BaseObject in baseObjects)
129 {
130 var found:Boolean = false;
131 for each (var removedObject:BaseObject in removedBaseObjects)
132 {
133 if (removedObject == baseObject)
134 {
135 found = true;
136 break;
137 }
138 }
139
140 if (!found)
141 baseObject.shutdown();
142 }
143 }
144
145 protected function insertNewBaseObjects():void
146 {
147 for each (var baseObject:BaseObject in newBaseObjects)
148 baseObjects.addItem(baseObject);
149
150 newBaseObjects.removeAll();
151 }
152
153 protected function removeDeletedBaseObjects():void
154 {
155 for each (var removedObject:BaseObject in removedBaseObjects)
156 {
157 var i:int = 0;
158 for (i = 0; i < baseObjects.length; ++i)
159 {
160 if (baseObjects.getItemAt(i) == removedObject)
161 {
162 baseObjects.removeItemAt(i);
163 break;
164 }
165 }
166
167 }
168
169 removedBaseObjects.removeAll();
170 }
171 }
172 }

我们从EngineManager类讲起。这个类用来完成3d引擎的初始化。它继承自UIComponent,这样我们就能像使用其他的flex组件一样,直接把它放到Application标签中。一会我们就可以在Alternativa1.mxml中看到他。

在EngineManager的构造函数中,我们添加了一个事件监听器。它可以在EngineManager放到显示列表时,完成一些初始化操作。有一点我们不必担心,该事件一旦发生,stage属性将不为空。

在init函数中,我们做了一些Alternativa初始化操作。我们创建了4个很重要的东西:Scene3D,Camera3D,CameraController和View。Scene3D本质上是一个容纳其他物体的容器(功能同sprite)。Camera3D摄像机,从名字我们就能知道他的作用,他就像3d世界中的眼睛。CameraController为我们提供了鼠标和键盘控制camera,同时做一些简单的物体碰撞检测。使用CameraController我们只需要六行代码,就可以移动和控制3d世界,这真是一件很棒的事情。最后还有一个View,他用来把3d的影像转化成2d图片显示在显示器上。


你可能注意到,我们使用了一个FPS.init(stage).方法。这个方法用来在舞台上显示每秒的内存使用和帧率。对于程序调试,他是一个很有用的工具,但是在最终的发布版本,这个方法是可以注释掉的。

一旦Alternativa 引擎初始化,我们需要增加两个事件监听。一个是用来响应窗口大小改变(stage.addEventListener(Event.RESIZE, onResize),另一个用来不停渲染( stage.addEventListener(Event.ENTER_FRAME, onEnterFrame)。我们捕捉窗口大小变化事件,以便让View 做出相应大小改变。帧频渲染可以不停渲染当前3d场景。


帧频渲染是3D程序运行的基本概念。渲染包括两个部分,第一部分(游戏逻辑)是程序自身的更新:游戏中的运动和游戏逻辑处理。第二部分(屏幕渲染)就是3d engine的逐帧屏幕渲染,可以显示3d世界的变化。

第一部分的更新是由BaseObject 这个类完成的。你会在onEnterFrame 函数看到,我们用从BaseObjects取出单个BaseObject,并调用它的enterFrame 方法。enterFrame 方法是BaseObject 里重量级方法,他允许继承自BaseObject 的子类方便的进行自我渲染更新。在MeshObject 和RotatingBox 类中会看到他。


 

最后在init方法中我们调用了ApplicationManager.Instance.startupApplicationManager().在讲解这个以前,我们先把程序的逻辑和engine逻辑做分离。EngineManager的重要作用就是管理Alternativa引擎和不停渲染。

下面我们接着做另一件事,创建ApplicationManager 类。

 

代码

1 package
2 {
3
4 import mx.core.Application;
5
6 /**
7 * The ApplicationManager holds all program related logic.
8 */
9 public class ApplicationManager
10 {
11 protected static var instance:ApplicationManager = null;
12
13 public static function get Instance():ApplicationManager
14 {
15 if (instance == null)
16 instance = new ApplicationManager();
17 return instance;
18 }
19
20 public function ApplicationManager()
21 {
22
23 }
24
25 public function startupApplicationManager():ApplicationManager
26 {
27 var rotatingBox:RotatingBox = new RotatingBox().startupRotatingBox();
28 Application.application.engineManager.cameraController.lookAt(rotatingBox.model.coords);
29
30 return this;
31 }
32
33 }
34 }

 

ApplicationManager类是个单例类(不明白的自己百度)。该类中仅有一个名为startupApplicationManager的方法,它会返回类本身的唯一实例,在这个方法中我们还创建了一个RotatingBox(旋转多面体),并把它指向给摄像机。建立一个类,就在里面写了两行代码,似乎有些多余,但是对于一个复杂的程序来说,这样做有助于将程序逻辑和引擎逻辑分离。

 

 

代码

1 package
2 {
3 import mx.core.Application;
4
5 /**
6 * The BaseObject class allows extending classes to update themselves during the render loop.
7 */
8 public class BaseObject
9 {
10 public function BaseObject()
11 {
12
13 }
14
15 /**
16 * Must be called by all extending classes when being created. Adds this object to the list of BaseObjects maintained
17 * by the EngineManager.
18 */
19 public function startupBaseObject():void
20 {
21 Application.application.engineManager.addBaseObject(this);
22 }
23
24 /**
25 * Must be called by all extending classes when being destroyed. Removes this object to the list of BaseObjects maintained
26 * by the EngineManager.
27 */
28 public function shutdown():void
29 {
30 Application.application.engineManager.removeBaseObject(this);
31 }
32
33 /**
34 * This function is called once per frame before the scene is rendered.
35 *
36 * @param dt The time in seconds since the last frame was rendered.
37 */
38 public function enterFrame(dt:Number):void
39 {
40
41 }
42 }
43 }

 

 

 

 

代码

1 package
2 {
3 import alternativa.engine3d.core.Object3D;
4 import alternativa.engine3d.materials.SurfaceMaterial;
5
6 import mx.core.Application;
7
8 public class MeshObject extends BaseObject
9 {
10 public var model:Object3D = null;
11
12 public function MeshObject()
13 {
14 super();

抱歉!评论已关闭.