Papervision3D
PV3D是一个开源的遵循MIT协议的使用AS3代码写成的3D引擎。这篇文章旨在教会各位如何使用PV3D完成一个HELLOWORD式的3D程序,同时也是这篇教程的最近更新。PV3D2.0
Alpha(也称GW)对于初学者来说使用PV3D最大的障碍在于如何安装PV3D,由于对版本控制软件不熟是造成无法完成PV3D安装的主要原因,第一部分的三节阐述了这个问题,但是不是这篇文章的主要内容,如果你对版本控制软件不熟悉的话,那么你可以看看这部分。
【笔者注:】安装PV3D完全没有必要使用版本控制软件,PV3D说白了就是一个FLEX的库,如果你知道如何在FLEX中使用和导入库,那么你完全没有必要使用版本控制软件,笔者的做法是到GOOGLE
CODE网站去下载一个ZIP包,软后解压缩到一个文件夹,将该文件夹包含在我的项目的库目录中就可以了,至于说更新,那么重新下载一个就搞定了。
再者版本控制软件的使用教程,网上多如牛毛,我在这里也就不再累述了。第一节的三个部分都不做翻译,在译文中直接略去,望大家谅解
省略PV3D安装部分。
Papervision3D
at the following link then skip to the “Foundation of Papervision3D”
section:
·
Revision
435: /trunk/branches/GreatWhite/src
If
you don’t know what to do with that link, then continue on reading the links in
the first three sections.
Download
First,
you need to download Papervision3D using subversion. Follow the instructions at
either of these sites:
·
How
Can I Download Papervision3D?
·
Downloading
Papervision3D Alpha Great White
Classpath类路径
:为PV3D设置一个源代码文件夹
·
如果使用的是Flash:
·
关于如何设置和修改源文件路径
·
如果使用的是FLEX:
·
准备一个PV3D的项目
Document
Class文件类
Create
a document class to hold the required ActionScript:创建一个源文件
·
如果使用的是Flash:
·
使用AS3.0创建一个新的文档类
·
Using
Flex: 如果使用的是FLEX:
·
创建一个新的AS工程
·
使用FLASHDEVELOP
集成环境
·
创建一个PV3D项目
Foundation
of Papervision3D PV3D基础
.我尽量使得代码看起来简单以适应那些新上手AS3.0的用户,但是我还是要假定你们知道类的基础,如何写方法,如何实例化对象等等,如果还不懂得这些的话,那么你可以参看OREILY的AS3.0编程基础一书,对你非常有帮助,当我实例化对象的时候,我同时还假定了你自己会去导入那些我遗漏的包。
:每一个PV3D应用程序都至少要包含这四个类:Viewport3D,
Scene3D, Camera3D/ BasicRenderEngine(可选),在我进行详细的讲解之前请先浏览一下下面的代码。
package{
import flash.display.Sprite;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
public class Main extends Sprite{
private var viewport:Viewport3D;
private var scene:Scene3D;
private var camera:Camera3D;
private var renderer:BasicRenderEngine;
public function Main(){
initPapervision3D();
}
private function initPapervision3D():void{
viewport = new Viewport3D();
addChild(viewport);
scene = new Scene3D();
camera = new Camera3D();
renderer = new BasicRenderEngine();
renderer.renderScene(scene, camera, viewport);
}
}
}
Viewport3D视口
可以将Viewport3D视口看成是PV3D的一扇窗户,透过这扇窗户我们才能看见PV3D世界里的东西。仅此而已,视口没有其他的功能,你可以将窗口开在墙上,可以决定窗口的大小,仅此而已。使用这个类之要记得创建之后将其加入舞台就可以了。看看下面的代码
private var viewport:Viewport3D = new Viewport3D();
addChild(viewport);
作为参考我将视口的缺省属性列在下面,当然用户可以根据各自的喜好进行修改。在未来的文章中我们将讨论autoClipping
和
autoCulling
Viewport3D(viewportWidth:Number = 640, viewportHeight:Number = 480,
autoScaleToStage:Boolean = false, interactive:Boolean = false,
autoClipping:Boolean = true, autoCulling:Boolean = true)
Scene3D场景
继续我们的窗口比喻,Scene3D通过窗口展示所有你能看见的3D物体:天空,大地,以及这之间的一切。然而Scene3D只是一个空的场景。要显示的内容需要创建后逐一添加到场景,场景如下创建:
private
var scene:Scene3D = new Scene3D();
Camera3D镜头
如果没有一个人来欣赏着窗户和窗户外的美景的话,那真的是没有什么价值。很幸运,PV3D的开发者创建了镜头来捕捉动作,镜头也与许你设置X,Y,Z坐标来确定你从哪个角度来欣赏这个美景,想象一个第一人称设计或者飞行游戏,你移动着你的位置来观察现有的场景,对于Camera3D来说也是这样的,你移动镜头,那么整个Scene3D根据你当前的位置调整
Papervision3D
provides three cameras with varying functionalities:PV3D提供了3只能够镜头来适应你不同的需求
·
•要求目标朝着而且永远朝着对象看,而不管他自己当前的位置
·
•提供了自由的可以在空间任意角度方向观察的方法,例如yaw(),
pitch(), 和
roll()来调整镜头的角度,而moveForward(),
moveBackward(); moveLeft(), moveRight(), moveUp(), 和
moveDown()来调整镜头的位置,例如如果你要将镜头放置在直接朝向某人脸部的话那么你需要调用moveBackward(),虽然你一直盯着那个人的脸看,但是你离他越来越远。换个角度说,如果你把镜头放在那个人的头上,调用pitch()对着那个人看,然后再调用moveBackward(),这时虽然你在空中慢慢上升,但是你仍然朝着那个人看。
·
•截镜头-能够像FreeCamera3D自由镜头那样移动,但是它只能渲染你所决定的近距离或者是远距离的物体。
BasicRenderEngine基本渲染引擎
:在PV3D的世界里,你就是上帝,也就是说你得来决定世界什么时候开始存在,如果没有BasicRenderEngine来渲染你的世界,那么你的世界就不会存在,因此你可以自己有的决定这个引擎的开始和结束,BasicRenderEngine通过你设置的镜头的位置来渲染你的场景里的所有的物品
private var renderer:BasicRenderEngine = new BasicRenderEngine();
//Usually within an Event.ENTER_FRAME handler so the scene
renders in each frame
renderer.renderScene( scene, camera,
viewport );
即使你有许多的场景,视口,或者镜头你还是只需要一个渲染引擎来渲染所有的东西
//A snippet of multiple scenes, cameras, and viewport handled by one
renderer renderer.renderScene( scene, camera, viewport );
renderer.renderScene( scene2, camera2, viewport2 );
3D
Objects3D物体
3D
Coordinates3D坐标
在我们进入创建对象之前,让我们先了解一下物体在3D的空间里,是如何放置的。
在FLASH的2D世界里,你在舞台里放置对象的时候,坐标系是传统的计算机坐标系:左上角是原点,X轴向右增加,Y轴向下增加,然而在PV3D的世界里这一切就被颠覆了,原点位于场景的中心,镜头默认放置在(0,0,-1000)位置处。
【笔者注:】我想3D的坐标系对于我们中国的开发者来说就不必累述了吧,我们在高中学过的立体几何远比这个复杂许多,外国人的数学一般都比较烂,所以他们需要详细的学习这方面的知识,但是对于中国人来说真的是可以免了。
同时也要记住,你能看见的物体移动的距离和你镜头放置的位置是很有关系的,越近物体看起来就移动的越多,你不能在依赖于你在传统的2D世界里积累起来的项目或是经验,镜头放置在缺省的位置上再来考虑下面的例子
·
•
x = 10; //也就是场景中心右方10个单位
·
•
x = -10; //场景中心左方10个单位
·
•
y = -10; //场景中心下方10个单位
·
•
z = -10; //场景中心前方(离镜头近)10个单位
如果你非要弄清楚在2D的屏幕上3D是怎么实现的,那么准备你肚子里的数学货色去阅读下面的文章
http://en.wikipedia.org/wiki/Quarterion
http://www.adobe.com/devnet/flash/articles/3d_classes_03.html
http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm
即使你不懂得文章中提到的数学知识,你应该大致懂得了3D对象是在3D坐标的基础上创建起来的,这些3D的坐标或者说是顶点是通过三角形,倾斜之后的绘制使得物体看上去具有3D效果的。PV3D使用画家算法来排序那些三角形的可见度,对于FP来说画家算法效率很高,但是如果三角形发生重叠的话,画家算法就会失效,要解决这个问题只有创建更多的段来减少三角形重叠的问题
Plane平面
我认为对于PV3D来说屏幕是所有项目中最有用的3D物体,特别是如果该项目是交互式的,但是奇怪的是,严格的来说平面不能被称为3D物体因为他没有厚度,PV3D里平面的形象表示是两个直角三角形沾在一块儿就成了一块平面,记住场景保存了你所能观察到的所有的物体,如果你要使用平面,那么不要忘了,创建了它之后将其添加到场景里去
var plane:Plane = new Plane();
scene.addChild(plane);
平面缺省使用了线帧材料(在以后的文章里讨论)并且宽和高都是500,因此上面的代码会创建一个放置在场景中心的(0,0,0)DE
宽和高都是500面对着镜头的平面,代码如下:
SegmentsW
和
segmentsH,以及“段”数目,宽,高,更多数量的端避免了平面在旋转的时候扭曲等错误,下面的例子展示了SW,SH两个属性分别为4和3时候的情况
Plane( material:MaterialObject3D=null, width:Number=0,
height:Number=0, segmentsW:Number=0, segmentsH:Number=0,
initObject:Object=null )
材料,宽,高,这些属性很容易就能理解。在平面的方法里分别设置其“段”的
如果你创建了许多的平面,而且每一个都要进行SEGMENT的设置的话,那你可能要抓狂了,(但是SEGMENT确实提高了平面的细节程度)FP要处理的三角形的个数依赖于你的程序,但是尽量避免使这个数目超过2000
最后一个可选的属性参数,initObject同样能够存储3D对象的x,
y, z, rotationX, rotationY, rotationZ, scaleX, scaleY, scaleZ,属性,在创建了3D对象之后你可以直接设置这个值,下面的例子快速的展现了这一点
var m:WireframeMaterial = new WireframeMaterial();
//width and height
var w:Number = 800;
var h:Number = 800;
//segmentsW and segmentsH
var sW:Number = 1;
var sH:Number = 1;
var initObject:Object = new Object();
initObject.x = 100;
initObject.rotationY = 30;
initObject.scaleZ = 20;
//Option #1 using initObject可选1使用initObject
var plane:Plane = new Plane(m, w, h, sW, sH, initObject);
scene.addChild(plane);
//Option #2 setting properties directly可选2直接设置
var plane:Plane = new Plane(m, w, h, sW, sH, initObject);
plane.x = 100;
plane.rotationY = 30;
plane.scaleZ = 20;
scene.addChild(plane);
.关于平面的最后一点,如果你钉住一个平面,你就会注意到从屏幕的另一侧来看的时候平面就消失了,如果你有平面的双面纹理材料那么你需要设置平面的doubleSided属性,如下:
material.doubleSided
= true;
Sphere球体
你可以和创建屏幕非常类似的那样来创建一个球体
var sphere:Sphere = new Sphere();
scene.addChild(sphere);
球体的缺省参数和平面很相似,球体初始化的时候只需要一个半径参数,这一点和平面是不同的,【BLUR,BLUR
BLUR球体的俄数学知识介绍译者注】缺省参数如下:
Sphere( material:MaterialObject3D=null, radius:Number=100,
segmentsW:int=8, segmentsH:int=6,
initObject:Object=null )
为了简单起见,锥体和柱体就简单的列出了创建方法了,原理和上面描述的也差不多:
Cone( material:MaterialObject3D=null, radius:Number=100,
height:Number=100, segmentsW:int=8, segmentsH:int=6,
initObject:Object=null )
Cylinder( material:MaterialObject3D=null, radius:Number=100,
height:Number=100, segmentsW:int=8, segmentsH:int=6,
topRadius:Number=-1,
initObject:Object=null )
Cube正方体
如果拿出6个平面并将其组装为一个盒子,你能像到什么?一个立方体
到现在你已经懂得了如何创建3d对象,除了立方体引入了一个MaterialsList(稍侯讨论),阅读一下如何创建一个立方体你大概就明白了如何创建一个MaterialsList
var frontMaterial:WireframeMaterial = new WireframeMaterial();
var backMaterial:WireframeMaterial = new WireframeMaterial();
var leftMaterial:WireframeMaterial = new WireframeMaterial();
var rightMaterial:WireframeMaterial = new WireframeMaterial();
var topMaterial:WireframeMaterial = new WireframeMaterial();
var bottomMaterial:WireframeMaterial = new WireframeMaterial();
var materialsList:MaterialsList = new MaterialsList();
materialsList.addMaterial(frontMaterial, "front");
materialsList.addMaterial(backMaterial, "back");
materialsList.addMaterial(leftMaterial, "left");
materialsList.addMaterial(rightMaterial, "right");
materialsList.addMaterial(topMaterial, "top");
materialsList.addMaterial(bottomMaterial, "bottom");
var cube:Cube = new Cube(materialsList);
scene.addChild(cube);
如果镜头缺省设置的话,立方体渲染的时候看起来是剧中的,镜头直对着立方体,没有任何角度的话,立方体看起来就像一个平面,你可以通过设置立方体的rotation属性来观察立方体的全部效果,下面是立方体的全部缺省参数
Cube(
materials:MaterialsList, width:Number=500, depth:Number=500,
height:Number=500,
segmentsS:int=1, segmentsT:int=1, segmentsH:int=1,
insideFaces:int=0,
excludeFaces:int=0, initObject:Object=null )
段需要稍加解释,然而函数和平面的段是基本一致的。
·
•
segmentS -段径向的数目(如果是平面的话就是和宽垂直)默认为1
·
•
segmentsT -. 段纵向的数量(如果是平面的话就是和厚度垂直),缺省和sS一样
·
•
segmentsH -水平方向的段数量(平面的话就是和高垂直)缺省和sS一样
insideFaces参数决定了立方体内部的面是如何渲染的,这对于将镜头放在立方体内部是有效的,使用以下的立方体的静态参数来确定你想要包含的面
·
•
Cube.NONE
·
•
Cube.FRONT
·
•
Cube.BACK
·
•
Cube.LEFT
·
•
Cube.RIGHT
·
•
Cube.TOP
·
•
Cube.BOTTOM
·
•
Cube.ALL
只需要简单的创建一个insideFaces整型常量然后将其添加到合适的地方。例如:如果你只要立方体的内部的上面那么可以这么写
var
insideFaces:int = Cube.TOP;
var
cube:Material = new Cube(m, w, d, h, sS, sT, sH,
insideFaces);
如果你需要立方体内的左和右面那么可以这么写
var
insideFaces:int = Cube.LEFT + Cube.RIGHT + Cube.BOTTOM;
var
cube:Material = new Cube(m, w, d, h, sS, sT, sH,
insideFaces);
如果你想要所有的面除了前面,那么可以这么写
var
insideFaces:int = Cube.ALL - Cube.FRONT;
var
cube:Material = new Cube(m, w, d, h, sS, sT, sH,
insideFaces);
下一个参数excludeFaces原理是一样的,但是它的作用是排除那些你不想要的面
Collada3DMAX支持的文件
这才是PV3D使人兴奋的地方,你可以通过你熟悉的3D工具创建你想要的3D模型,然后将其到处为COLLADA文件然后通过PV3D的DAE类进行装载,不幸的是这一点的讨论足足需要一篇文章,但是如果你想看看的话,可以点击下面的例子
Loading
Collada Files into Papervision3D
Testing
Kinematics with Papervision3D Collada
DCC
Tutorials
Enough
Talk, Let’s See Code!谈的够多了,看看代码吧
我打赌你一定觉得学的够多了,而迫不及待的要敲击键盘了,下面我们就给出一个完整的PV3D的例子
package {
import flash.display.Sprite;
import flash.events.Event;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
[SWF ( width = '640', height = '480', backgroundColor = '#ffffff',
frameRate = '31' ) ]
public class RotatingCubeExample extends Sprite {
private var viewport:Viewport3D;
private var scene:Scene3D;
private var camera:Camera3D;
private var renderer:BasicRenderEngine;
private var cube:Cube;
public function RotatingCubeExample(){
'initPapervision3D();
createCube();
beginRender();
}
private function initPapervision3D():void{
viewport = new Viewport3D();
addChild(viewport);
scene = new Scene3D();
camera = new Camera3D();
renderer = new BasicRenderEngine();
}
private function createCube():void{
var allM:WireframeMaterial = new WireframeMaterial();
var m:MaterialsList = new MaterialsList();
m.addMaterial(allM, "all");
//width, depth, height
var w:Number = 300;
var d:Number = 500;
var h:Number = 700;
//segments S, T, and H
var sS:int = 2;
var sT:int = 3;
var sH:int = 4;
cube = new Cube(m, w, d, h, sS, sT, sH);
scene.addChild(cube);
}
private function beginRender():void{
//calls the render function every frame
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
//rotates around the vertical axis
cube.yaw(2);
//rotates around the lateral axis
cube.pitch(1);
renderer.renderScene(scene, camera, viewport);
}
}
}
常见的错误:救命!我看不见任何东西
·
1.你恰当的导入了所有的类吗?
·
2.你将场景加入容器了吗?
addChild(viewport);
·
3.你将所有的对象都加入到了场景里吗?
scene.addChild(cube);
·
4.你渲染了你的场景吗?
renderer.renderScene(scene,
camera, viewport);
Just
Getting Started仅仅是开始
我希望你认识到这篇文章所触及的不过是冰山的一角,下面的文章将讨论纹理方面的知识,这样你就可以做出更加好,更加漂亮的3D对象了
Thanks致谢
我想要谢谢PV3D的所有开发人员,给予我们这样优秀的PV3D产品,我也要谢谢邮件列表中,开源社区的所有人,你们共同制造了这样的一个优秀产品
·
Core
team
·
Carlos
Ulloa
·
John
Grden
·
Ralph
Hauwert
·
Tim
Knip
·
Andy
Zupko
·
Committer
team
·
Mr.doob
·
De'Angelo
Richardson
·
Tink
·
Seb-Lee
Delisle
·
Contributors
·
Patrick
Pietens
·
Ron
Valstar
源文档
<http://www.insideria.com/2008/02/papervision3d-part-1-foundatio.html>
Papervision3D
Papervision3D
is an open-source, MIT licensed 3D engine written in ActionScript 3.0 for Flash.
This article will teach you how to set up your first Papervision3D application
with the most recent revision as of this writing, Papervision3D 2.0 Alpha,
otherwise known as “Great White.” The great barrier for beginners is usually
“installing” Papervision3D as they are unfamiliar with subversion, classpaths,
and documents classes. The first three sections address these issues with
off-site tutorials as that process is not within the scope of this article. So
if you’re familiar with the subversion process and setting up an ActionScript
3.0 project, check out Papervision3D at the following link then skip to the
“Foundation of Papervision3D” section:
·
Revision
435: /trunk/branches/GreatWhite/src
If
you don’t know what to do with that link, then continue on reading the links in
the first three sections.
Download
First,
you need to download Papervision3D using subversion. Follow the instructions at
either of these sites:
·
How
Can I Download Papervision3D?
·
Downloading
Papervision3D Alpha Great White
Classpath
Set
up a classpath that points to the Great White “src”
directory:
·
Using
Flash:
·
About
Setting and Modifying the Classpath
·
Using
Flex:
·
Preparing
a Papervision3D Project
Document
Class
Create
a document class to hold the required ActionScript:
·
Using
Flash:
·
Creating
a Document Class with ActionScript 3.0
·
Using
Flex:
·
New
-> ActionScript Project”
·
Using
FlashDevelop:
·
Preparing
a Papervision3D Project
Foundation
of Papervision3D
I’ll
keep the code as simple as I can for those of you new to ActionScript 3.0, but I
will assume you have a basic understanding of importing classes,
declaring/instantiating variables, and writing/calling methods. If not,
O’Reilly’s “Essential ActionScript 3.0” is a great place to start. When I instantiate
objects in code snippets, I’ll assume you understand you need to import the
relevant classes.
Every
Papervision3D application requires four classes: Viewport3D, Scene3D, Camera3D
(or alternatives), and BasicRenderEngine (or alternative). Glance at the
following typical set up of a Papervision3D project before I dive into a full
explanation:
package{
import
flash.display.Sprite;
import
org.papervision3d.cameras.Camera3D;
import
org.papervision3d.render.BasicRenderEngine;
import
org.papervision3d.scenes.Scene3D;
import
org.papervision3d.view.Viewport3D;
public class Main extends Sprite{
private var
viewport:Viewport3D;
private var
scene:Scene3D;
private var
camera:Camera3D;
private var
renderer:BasicRenderEngine;
public function Main(){
initPapervision3D();
}
private function
initPapervision3D():void{
viewport = new
Viewport3D();
addChild(viewport);
scene = new
Scene3D();
camera = new
Camera3D();
renderer = new
BasicRenderEngine();
renderer.renderScene(scene,
camera, viewport);
}
}
}
Viewport3D
Think
of a Viewport3D as a window to the world of Papervision3D. Windows allow you to
see outside, but they serve no other function. You can position a window on the
wall or change its width and height, but that’s really about it. The same is
true with Viewport3D. You can change the “x”, “y”, “width”, and “height” of the
Viewport3D, but its only true functionality is to let you look at the 3d scene
inside of it. To use a viewport, create it then add it to the
stage.
private
var viewport:Viewport3D = new Viewport3D();
addChild(viewport);
For
reference, the default parameters of Viewport3D, which you can adjust to your
liking, are as follows. I’ll cover interactive, autoClipping, and autoCulling in
a future article:
Viewport3D(viewportWidth:Number
= 640, viewportHeight:Number = 480,
autoScaleToStage:Boolean
= false, interactive:Boolean = false,
autoClipping:Boolean
= true, autoCulling:Boolean = true)
Scene3D
To
continue with the window metaphor, a Scene3D would hold everything you could see
looking through the window: the ground, the sky, and everything in-between. Yet
the Scene3D is still just empty 3D space. You have to add the ground, the sky,
the trees, etc., by adding 3d objects to your Scene3D. A scene3D is created as
follows:
private
var scene:Scene3D = new Scene3D();
Camera3D
A
window and an outside world are pretty worthless if there’s no one there to
witness their beauty. Luckily for you, the developers of Papervision3D created
cameras to capture all the action. A Camera3D allows you to set the x, y, and z
coordinates from where you want to capture the action. Imagine a first-person
shooter or flight simulator. You move your character around and the surrounding
area adjusts to your current position. The same idea applies to Camera3D
movement: you move the camera and the entire Scene3D adjusts to its current
position.
Papervision3D
provides three cameras with varying functionalities:
·
•
Camera3D- requires a target to “look at” and will always “look at” that target
regardless of position
·
•
FreeCamera3D- moves freely through 3D space in every angle and direction.
Includes methods such as yaw(), pitch(), and roll() to adjust the camera’s
viewing angle as well as moveForward(), moveBackward(); moveLeft(), moveRight(),
moveUp(), and moveDown() to adjust the camera’s position based on its viewing
angle. For example, if you position the camera looking straight at someone’s
face then call moveBackward(), you will move farther and farther back from that
person’s face while still looking straight their face. On the other hand, if you
position the camera above the person, pitch() the camera to look straight down
at their hair, and then call the same moveBackward() method, you will lift the
camera higher into the sky while continuing to look at the person’s hair.
·
•
FrustumCamera3D- moves like FreeCamera3D, but only renders the objects within a
field of view, far distance, and near distance that you determine.
BasicRenderEngine
In
the world of Papervision3D, you’re God. That means you get to decide when the
world exists. Without the BasicRenderEngine class rendering your world, it just
won’t exist. So you can start and stop the engine as you please. The
BasicRenderEngine renders a Scene3D from the Camera3D position through the
Viewport3D that you choose:
private
var renderer:BasicRenderEngine = new BasicRenderEngine();
//Usually
within an Event.ENTER_FRAME handler so the scene
renders
in each frame
renderer.renderScene( scene, camera,
viewport
);
Even
if you have multiple scenes, viewports, or cameras, you still only need one
BasicRenderEngine to handle all of the rendering:
//A
snippet of multiple scenes, cameras, and viewport handled by one
renderer
renderer.renderScene( scene, camera, viewport );
renderer.renderScene(
scene2, camera2, viewport2 );
3D
Objects
3D
Coordinates
Before
diving into creating objects, let’s take a look at how objects are positioned in
3D space as opposed to traditional Flash projects.
In
Flash, you position an object on the stage based on x:0 and y:0 being in the
upper-left corner. Increasing x moves an object to the right and increasing y
moves an object down. Conversely, in Papervison3D x:0, y:0, and z:0 are in the
center (not the upper-left) of the Scene3D. Since the Camera3D defaults to x:0,
y:0, z:-1000 and points at the origin (x:0, y:0, z:0), increasing x moves the
object right, increasing y moves the object up, and increasing z moves the
object toward the horizon.
Also,
remember the amount of movement you will see is based on how close the camera is
to the 3d object. The closer the camera the more objects will appear to move.
You cannot rely on pixels like you can in a traditional two dimensional Flash
project. Consider the following examples based on the default camera
position:
·
•
x = 10; //means 10 units right of Scene3D’s center
·
•
x = -10; //means 10 units left of Scene3D’s center
·
•
y = -10; //means 10 units below Scene3D’s center
·
•
z = -10; //means 10 units closer to the camera from Scene3D’s center (remember
Camera3D defaults to z:-1000 so moving from 0 to -10 brings the object closer to
-1000.)
If
you’re the type of person who must understand how 3D coordinates are possible
within in a 2D Flash Player, put on your math hat and read up on
quarterions:
http://en.wikipedia.org/wiki/Quarterion
http://www.adobe.com/devnet/flash/articles/3d_classes_03.html
http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm
Even
if you don’t understand the math involved in those articles, you probably
understand that 3D objects are made up groups of 3D coordinates. These 3D
coordinates (also known as vertices) form triangles. The triangles form a
polygon mesh or, in layman’s terms, a 3D object.
On
a side note, Papervision3D uses the Painter’s Algorithm to sort the visibility
of those triangles. The Painter’s Algorithm evaluates the sorting quickly (ideal
for Flash Player), but can fail if triangles overlap. You typically resolve this
issue by creating more segments in your 3D object to give less chance that the
triangles overlap.
Plane
I
consider Planes to be the most useful 3D objects for most Papervision3D
projects, especially if the project is interactive. Oddly enough, a Plane does
not technically qualify as a 3D object as it has no depth. A Plane is simply two
triangles stuck together to form a rectangle. Remember, the Scene3D holds all of
your 3D objects. So to use a plane, create it then add it to the
Scene3D.
var
plane:Plane = new Plane();
scene.addChild(plane);
A
Plane defaults to a WireFrameMaterial (discussed in a later article) with a
width of 500 and height of 500. So using the above code will result in a
wireframe Plane centered at x:0, y:0, and z:0 with a width and height of 500
facing the camera (assuming the camera is in its default position discussed
earlier). When you pass a material with an image inside it, the Plane will
default to the width and height of the bitmap of that image. The parameters
available for a Plane are as follows:
Plane(
material:MaterialObject3D=null, width:Number=0,
height:Number=0,
segmentsW:Number=0, segmentsH:Number=0,
initObject:Object=null
)
Material,
width, and height are pretty self-explanatory. SegmentsW and segmentsH set the
number of segments in the width and height of the Plane respectively. Multiple
segments help to avoid the distortion of an image when the Plane starts rotating
as well as the depth sorting of the triangles as mentioned earlier. The
screenshot below demonstrates a Plane with four segmentsW and three
segmentsH.
Be
wary when creating many Planes as each additional width or height segment you
create tacks on two more triangles (essentially forming another rectangle inside
the Plane to give the plane more detail). The number of triangles Flash Player
can handle varies depending on your application, but generally try and keep the
triangle count below 2000.
The
last optional parameter, initObject, can store the initial x, y, z, rotationX,
rotationY, rotationZ, scaleX, scaleY, scaleZ, and “extra” parameters.
Alternatively, you can directly set the listed properties after instantiating
your Plane. A quick example will explain nicely:
var
m:WireframeMaterial = new WireframeMaterial();
//width
and height
var
w:Number = 800;
var
h:Number = 800;
//segmentsW
and segmentsH
var
sW:Number = 1;
var
sH:Number = 1;
var
initObject:Object = new Object();
initObject.x
= 100;
initObject.rotationY
= 30;
initObject.scaleZ
= 20;
//Option
#1 using initObject
var
plane:Plane = new Plane(m, w, h, sW, sH, initObject);
scene.addChild(plane);
//Option
#2 setting properties directly
var
plane:Plane = new Plane(m, w, h, sW, sH, initObject);
plane.x
= 100;
plane.rotationY
= 30;
plane.scaleZ
= 20;
scene.addChild(plane);
One
final note about Planes: if you spin a Plane, you’ll notice the plane will
disappear once you look at the other side. If you want to have a texture on both
sides of the Plane, you will need to enable the “doubleSided” property of your
material you pass into your Plane.
material.doubleSided
= true;
Sphere
You
create a Sphere very similarly to the way you create a
Plane:
var
sphere:Sphere = new Sphere();
scene.addChild(sphere);
A
Sphere’s default parameters closely resemble a Plane’s parameters as well. The
Sphere just takes a radius parameter instead of width and height. If you think
back to high school, you will probably recall the radius being the distance from
the center of the circle to the outer edge. As opposed to the simplicity of
width and height of a Plane, the Sphere now uses the radius to calculate the
distance between the center and the edges to create groups of three vertices
that make groups of triangles that make the Sphere. Pretty neat, huh? The
default parameters are as follows:
Sphere(
material:MaterialObject3D=null, radius:Number=100,
segmentsW:int=8,
segmentsH:int=6,
initObject:Object=null
)
For
brevity’s sake, a Cone and a Cylinder can be created similarly with the
following default parameters:
Cone(
material:MaterialObject3D=null, radius:Number=100,
height:Number=100,
segmentsW:int=8, segmentsH:int=6,
initObject:Object=null
)
Cylinder(
material:MaterialObject3D=null, radius:Number=100,
height:Number=100,
segmentsW:int=8, segmentsH:int=6,
topRadius:Number=-1,
initObject:Object=null
)
Cube
What
do you get when you take six Planes and organize them into the shape of a box? A
Cube!
By
now you should be getting the hang of creating 3D objects, but the Cube throws
in a curve ball by requiring a MaterialsList (discussed in a later article). You
will probably get the gist of how to use a MaterialsList by reading how to
create a Cube:
var
frontMaterial:WireframeMaterial = new WireframeMaterial();
var
backMaterial:WireframeMaterial = new WireframeMaterial();
var
leftMaterial:WireframeMaterial = new WireframeMaterial();
var
rightMaterial:WireframeMaterial = new WireframeMaterial();
var
topMaterial:WireframeMaterial = new WireframeMaterial();
var
bottomMaterial:WireframeMaterial = new
WireframeMaterial();
var
materialsList:MaterialsList = new MaterialsList();
materialsList.addMaterial(frontMaterial,
"front");
materialsList.addMaterial(backMaterial,
"back");
materialsList.addMaterial(leftMaterial,
"left");
materialsList.addMaterial(rightMaterial,
"right");
materialsList.addMaterial(topMaterial,
"top");
materialsList.addMaterial(bottomMaterial,
"bottom");
var
cube:Cube = new Cube(materialsList);
scene.addChild(cube);
The
Cube faces forward when rendered meaning, with the camera in the default z:-1000
looking at x:0, y:0, z:0 position, you will be looking directly at the back of
the Cube. Without any perspective, it will look exactly like a Plane. You can
easily set any of the Cube’s rotation properties to see the full effect (the
earlier Cube image was rotated slightly to show perspective). Now let’s cover
the default parameters of a cube:
Cube(
materials:MaterialsList, width:Number=500, depth:Number=500,
height:Number=500,
segmentsS:int=1, segmentsT:int=1, segmentsH:int=1,
insideFaces:int=0,
excludeFaces:int=0, initObject:Object=null )
The
segments require a little explaining, yet function in the same fashion as
Plane’s segments:
·
•
segmentS - Number of segments sagitally (plane perpendicular to width). Defaults
to 1.
·
•
segmentsT - Number of segments transversally (plane perpendicular to depth).
Defaults to segmentsS.
·
•
segmentsH - Number of segments horizontally (plane perpendicular to height).
Defaults to segmentsS.
The
insideFaces parameter determines which faces will be rendered on the inside of
the Cube. This is useful if you want to have the camera inside of the Cube for
the illusion of being trapped in a room. To set the faces you want to include,
use the following static public variables of Cube:
·
•
Cube.NONE
·
•
Cube.FRONT
·
•
Cube.BACK
·
•
Cube.LEFT
·
•
Cube.RIGHT
·
•
Cube.TOP
·
•
Cube.BOTTOM
·
•
Cube.ALL
Simply
create an insideFaces integer that describes which faces you want to see on the
inside and pass it as a parameter where appropriate. For example, if you want
just the top of the inside of the Cube to be rendered, write the
following:
var
insideFaces:int = Cube.TOP;
var
cube:Material = new Cube(m, w, d, h, sS, sT, sH,
insideFaces);
For
just the left, right, and bottom face:
var
insideFaces:int = Cube.LEFT + Cube.RIGHT + Cube.BOTTOM;
var
cube:Material = new Cube(m, w, d, h, sS, sT, sH,
insideFaces);
For
all the faces except the front face:
var
insideFaces:int = Cube.ALL - Cube.FRONT;
var
cube:Material = new Cube(m, w, d, h, sS, sT, sH,
insideFaces);
The
next parameter, excludeFaces, works exactly the same way, but excludes the faces
you don’t want. Think of it like taking the lid of a
shoebox.
Collada
This
is where Papervision3D gets really exciting: you create a model in your
preferred 3D modeling program (3ds max, Maya, Blender, Swift3D, etc.), export it
as a Collada file, and load it using the Papervision3D DAE class. Unfortunately,
this topic deserves an article unto itself, but here are a few demos to get you
on the right track:
Loading
Collada Files into Papervision3D
Testing
Kinematics with Papervision3D Collada
DCC
Tutorials
Enough
Talk, Let’s See Code!
I
bet you’re anxious to start tickling the keyboard to see if it laughs out a
working Papervision3D project. So let’s make a Cube and spin it using the Cube
yaw() and pitch() methods (Don’t fret, I’ll cover the details of yaw, pitch,
roll, etc. in future articles):
package
{
import
flash.display.Sprite;
import
flash.events.Event;
import
org.papervision3d.cameras.Camera3D;
import
org.papervision3d.materials.WireframeMaterial;
import
org.papervision3d.materials.utils.MaterialsList;
import
org.papervision3d.objects.primitives.Cube;
import
org.papervision3d.render.BasicRenderEngine;
import
org.papervision3d.scenes.Scene3D;
import
org.papervision3d.view.Viewport3D;
[SWF ( width = '640', height = '480',
backgroundColor = '#ffffff',
frameRate
= '31' ) ]
public class RotatingCubeExample extends
Sprite {
private var
viewport:Viewport3D;
private var
scene:Scene3D;
private var
camera:Camera3D;
private var
renderer:BasicRenderEngine;
private var
cube:Cube;
public function
RotatingCubeExample(){
'initPapervision3D();
createCube();
beginRender();
}
private function
initPapervision3D():void{
viewport = new
Viewport3D();
addChild(viewport);
scene = new
Scene3D();
camera = new
Camera3D();
renderer = new
BasicRenderEngine();
}
private function
createCube():void{
var allM:WireframeMaterial = new
WireframeMaterial();
var m:MaterialsList = new
MaterialsList();
m.addMaterial(allM,
"all");
//width, depth,
height
var w:Number =
300;
var d:Number =
500;
var h:Number =
700;
//segments S, T, and
H
var sS:int = 2;
var sT:int = 3;
var sH:int = 4;
cube = new Cube(m, w, d, h, sS, sT,
sH);
scene.addChild(cube);
}
private function
beginRender():void{
//calls the render function every
frame
addEventListener(Event.ENTER_FRAME,
render);
}
private function
render(e:Event):void{
//rotates around the vertical
axis
cube.yaw(2);
//rotates around the lateral
axis
cube.pitch(1);
renderer.renderScene(scene, camera,
viewport);
}
}
}
Common
Mistakes: Help! I Don’t See Anything!
·
1.
Did you properly import the Papervision3D classes?
·
2.
Did you “addChild()” your viewport?
addChild(viewport);
·
3.
Did you “scene.addChild()” your 3D Object?
scene.addChild(cube);
·
4.
Did you render your scene?
renderer.renderScene(scene, camera,
viewport);
Just
Getting Started
I
hope you realize that this article barely touched the tip of the Papervision3D
iceberg. The next article will cover the materials (sometimes known as textures)
so you can make your 3D objects look nice and pretty.
Thanks
I’d
like to thank all of the members of the Papervision3D team, everyone who has
ever helped anyone on the Papervision3D mailing list, and the community for
making such a wonderful open-source product:
·
Core
team
·
Carlos
Ulloa
·
John
Grden
·
Ralph
Hauwert
·
Tim
Knip
·
Andy
Zupko
·
Committer
team
·
Mr.doob
·
De'Angelo
Richardson
·
Tink
·
Seb-Lee
Delisle
·
Contributors
·
Patrick
Pietens
·
Ron
Valstar