绘制一个Box
参考《配置A3D开发环境》我们讲解测试环境的代码。新建一个项目Demo。打开Main.as,输入如下代码(加粗):
package
{
importalternativa.engine3d.core.Camera3D;
importalternativa.engine3d.core.Object3D;
importalternativa.engine3d.primitives.Box;
import flash.display.Sprite;
importflash.events.Event;
importflash.display.Stage3D;
/**
* ...
*@author yl
*/
public class Mainextends Sprite
{
//创建一个容器,存放3D场景的所有对象
private var rootContainer:Object3D = new Object3D();
privatevar camera:Camera3D;//创建摄像机
privatevar stage3D:Stage3D;//创建Stage3D对象
privatevar box:Box;//定义一个Box对象
……
}
开始的时候我们在package里面导入了需要用到的类,然后在Main类里定义了4个变量。
(1)Object3D是所有A3D中对象的基类。它是一个容器,能存放其他的3D对象。和MovieClip一样,我们能通过addChild方法来存放其他的3D对象。它拥有和MovieClip相似的属性,如x、y、z、rotationX等。
(2)Camera3D继承自Object3D。它被设计成渲染场景,它在屏幕上不输出任何东西,正确的显示3D对象是显示器的事情。我们看不见不在可可视范围外(场景外)的所有对象,它剔除所有不在可视区域的多边形,这样能节省CPU资源。下面有一段关于Camera3D的通俗解释:
Camera3D:三维摄像机。对于利用Camera来完成三维动画的想法,我一直觉得很是高明。想象一下,我们的眼睛就是摄像机。如果我们想观察一个物体的各个侧面,我们会用手转动这个物体,然后观察。我们为何不换一种思路,把物体放在那,而眼镜(自己的头)绕着物体转呢?这也就是Camera3D的作用。不但我们可以控制场景中物体的任意动画,我们也可以控制摄像机的不同位置与角度。想想CS,不就像是自己拿着摄像机在看一个三维世界吗?这样的设计更合理,也更具与人性的特点。那如何来控制摄像机呢?在A3D中也为我们设计了一下特定的类,后面的教程中将会给大家介绍。同时,在3D中,摄像机必须与View(视窗),相结合使用。那什么又是视窗呢?
引自:http://www.zcool.com.cn/article/ZMTEwMzY=.html
(3)Box是A3D中的3D对象,继承自Object3D。
(4)Stage3D 是Adobe在Flash Player11中引入的一套新的ActionScript API,这套API允许Flash利用硬件渲染3D画面。
以前,在Flash中的3D渲染是不经过硬件加速的。事实上,在Flash Player11以前的所有3D渲染都是软件渲染模式,也就是依靠CPU来完成的。软件渲染模式非常的慢,而且不能用来渲染很细节化的3D场景。
随着Flash Player 11的发布,新的机会来了。开发者可以充分利用3D硬件加速,而不是靠CPU来完成渲染。这种新的渲染模式把渲染工作交给了计算机的视频处理器,也就是所谓的GPU来处理。GPU是一种专门用来处理3D对象的硬件。
关于Stage3D的更多信息可以参考《Stage3D是如何工作的》。
通过下图我们详细了解一下Stage3D类。
1)支持硬件渲染的图像不包含在传统的 DisplayTree 中。 相反,它存在于一个特殊的 stage 中: stage3d。 任何应用程序都可以有四种不同的 stage3d 元素,应用程序至少需要一个Stage3D。它们全部作为层放置在彼此之上,但是却都位于 DisplayTree 之下。 这就保证了平面 Flash 对象总是与3D 图像重叠。可以通过下面代码获取:stage3D = stage.stage3Ds [0];
2)Stage3D willalways be behind any DisplayObject'a, that is, we can not place the spritebehind 3D graphics ...
3)Stage3D有一个Context3D属性。所有在3D场景中的对象都要上传自GPU内存Context3D。当所有的资源被加载完成和Content3D被建立,才能在显示器上显示图形。
publicfunction Main() {
……
stage3D= stage.stage3Ds[0];//获取stage3D对象
//创建Content3D后,调用onContextCreate
stage3D.addEventListener(Event.CONTEXT3D_CREATE,onContextCreate);
stage3D.requestContext3D();
}
(5)View类。View在构造方法中有定义:
privatefunction init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE,init);
// entrypoint
stage.align= "TL";//设置SWF在播放器或浏览器中的当前对齐方式,TL表示居顶左侧
//创建摄像机,0.1表示近裁剪距离,10000表示远裁剪距离
camera = new Camera3D(0.1, 10000);
//创建视窗,所有显示对象可由这个视窗观察
camera.view = new View(stage.stageWidth,stage.stageHeight);
……
//view不需要放入3D场景中,只需将摄像机观察的视窗加载进Sprite(显示列表)
addChild(camera.view);
}
现在我们只需要注意加粗的语句,View是一个视窗。我们来想想一下,你面前有扇门,门上有一个正方形小孔,你想通过小孔看看门后房子里是什么东西,而你和门之间有一段距离,就如下面的那张图。为了看得更全,你可以移动自己的眼镜(Camera3D),但是,你能看见的范围却只有那个孔那么大。这就是视窗View与摄像机Camera3D之间的关系,我们使用:camera.view 来组合他们的关系。视窗是用来观察场景(Scene3D.root)空间的一个窗口,所以视窗不用放在3D场景之中。
依据上图,总结一下前面的知识点。在一个A3D项目中
(1)至少有一个Stage3D对象,可以通过stage舞台类获取:
stage3D = stage.stage3Ds[0];//获取stage3D对象
(2)将所有显示的3D对象放入Object3D容器中(包括摄像机Camera3D)
private functioninit(e:Event = null):void {
……
rootContainer.addChild(camera);//将摄像机加载进容器
box = new Box(500, 500, 500, 5, 5, 5);
var material:FillMaterial = newFillMaterial(0xFF7700);
box.setMaterialToAllSurfaces(material);
rootContainer.addChild(box);//将box加载进容器
……
}
(3)将视窗加载进显示列表
……
//view不需要放入3D场景中,只需将摄像机观察的视窗加载进Sprite(显示列表)
addChild(camera.view);
……
(4)将所有的3D对象上传到GPU的内存Contex3D
(5)渲染stage3D
下面是后面2步的代码实现。
private function onContextCreate(e:Event):void {
//遍历在容器中所有资源
for each(var resource:Resource in rootContainer.getResources(true)) {
resource.upload(stage3D.context3D);//所有资源上传自GPU内存Content3D
}
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void {
//camera.rotationZ-= 0.01;
camera.render(stage3D);//渲染Stage3D,显示在Content3D的对象
}