PV3D-3.基本几何体
- 格式:doc
- 大小:338.00 KB
- 文档页数:19
实验/实训/实习
实训3创建标准基本体-几何球体
3.1 实训内容
●创建标准基本体—几何球体
●练习几何球体工具的使用
3.2 实训目的与要求
●掌握建立几何球体的操作
●掌握修改面板设置修改几何球体参数
●制作四面体、八面体、二十面体
3.3 实训相关知识
●创建命令面板
●标准基本体
3.4 实训环境
●硬件:教学做一体化机房、多媒体计算机、
●软件:Windows 8操作系统、3ds max 2012中文版
3.5 实训步骤
1.首先打开3ds max2012,“创建”-“几何体”-“标准基本体”,,在【对象类型】栏下单击“几何球体”按钮。
2.在视图窗口中按住鼠标左键并拖动,合适的大小松开鼠标,即可创建出一个几何球体。
3.在“修改面板”中设置修改几何球体参数。
【平滑】用于设置是否对球体进行平滑处理,不勾选则产生棱角。
【半球】可以将几何球体模型变为半球。
【基点面类型】:几何球体面越多,创建的几何球体越光滑。
【四面体】:
【八面体】
【二十面体】。
三维几何形的性质认识常见三维几何形的性质在几何学中,三维几何形是指在三维空间中存在的各种图形。
它们具有一些独特的性质,本文将介绍常见的三维几何形及其性质。
一、球体球体是一种具有全局对称性的三维几何形。
它的性质如下:1. 球体的表面是由无数个点所组成的,这些点到球心的距离都相等。
2. 球体的内部所有点到球心的距离都小于半径。
3. 球体的体积可以使用公式V = 4/3πr³来计算,其中V表示体积,r表示半径。
4. 球体是三维空间中具有最小表面积,最大体积的几何形。
二、立方体立方体是在三维空间中最常见的几何形。
它的性质如下:1. 立方体具有六个面,每个面都是正方形。
2. 立方体的六个面都相互平行,相邻面之间的边长相等。
3. 立方体的面、边和顶点的个数分别为6、12和8。
4. 立方体的体积可以使用公式V = a³来计算,其中V表示体积,a表示边长。
三、圆柱体圆柱体是由两个平行的圆面和一个侧面连接而成的几何形。
它的性质如下:1. 圆柱体的侧面是由直线与两个圆面上的点相连而组成的。
2. 圆柱体的高度是两个圆面之间的直线距离。
3. 圆柱体的底面积可以使用公式A = πr²来计算,其中A表示底面积,r表示半径。
4. 圆柱体的体积可以使用公式V = Ah来计算,其中V表示体积,A表示底面积,h表示高度。
四、圆锥体圆锥体是由一个圆锥面和一个顶点连接而成的几何形。
它的性质如下:1. 圆锥体的底面是一个圆,顶点与圆上的所有点相连。
2. 圆锥体的侧面是由直线与底面上的点相连而组成的。
3. 圆锥体的高度是圆锥面上的顶点到底面的距离。
4. 圆锥体的体积可以使用公式V = 1/3πr²h来计算,其中V表示体积,r表示底面半径,h表示高度。
五、棱柱体棱柱体是由两个平行且相等的多边形底面以及多条连接底面上对应顶点的线段所形成的几何形。
它的性质如下:1. 棱柱体的侧面是由直线与底面上的点相连而组成的。
3.2 制作摄像头实例介绍在本节中,我们将创建一个并不是十分复杂的摄像头,如图3-38所示。
在创建摄像头的过程中我们将接触到FFD(变形盒)修改工具和max中的一种非常重要的建模方法——布尔运算。
通过仔细的观察可以发现这个摄像头的模型具有明显的几何特性,观察摄像头的形体,可以发现在其外形上有明显的集合体之间相互拼凑的影子,所以就让我们联想到用简单的集合体,进行拼凑和剪切来完成模型框架的制作。
max复合物体类型中的布尔运算物体是创建这种物体的不二之选。
制作思路我们将延续上一节的制作思路,先使用max中的基本几何体创建出模型的基本框架,然后同时我们还将接触到一种对模型进行变形修改的方法——FFD变形盒修改命令,对模型的外型进行修改,再使用max中的一种非常重要的建模方法——布尔运算,制作出表面的凹槽。
图3-38 摄像头的效果图本实例包含的知识点如下:●使用基本几何体创建模型的基本框架●使用FFD变形盒修改命令,修改模型●布尔运算的基本方法●Loft放样操作3.2.1布尔运算制作框架操作步骤如下:(1)进入3ds max 6,单击Create(创建)按钮进入创建命令面板,在Object Type (对象类别)卷展栏中单击Sphere(球体)按钮,在Top视图中拖动鼠标创建一个球体图形。
(2)单击Modify(修改)按钮进入修改命令面板,在Parameters卷展栏中设置参数,其中Radius(半径)为100、Segments(片断数)为30。
(3)选中创建的球体,在修改命令面板的Modifier List下拉列表框中选择FFD(box)(变形盒)修改工具。
在修改命令面板上的FFD Paraments面板上点击(设置控制点数目)按钮,这时将会弹出如图3-39所示的Set FFD Dimensions对话框。
将长,宽,高三个方向上的控制点的数目都设置为4个,点击OK按钮完成控制点的设置。
这时在我们创建的球体表面出现如图3-40所示的控制点。
三维形的分类与特性三维形是指在三维空间中存在的几何形体,具有长度、宽度和高度三个维度。
在数学和几何学中,三维形的分类和特性是非常重要的内容,它们在各个领域的应用非常广泛。
本文将对三维形的分类和特性进行详细介绍。
一、分类在三维空间中,三维形根据其外形和特征可以分为多种类型。
以下是常见的几种三维形的分类:1. 立体体立体体是三维空间中具有无限多个点的集合,由无数个平面围成。
它可以是有界的,也可以是无界的。
立方体、球体、圆柱体等都属于立体体的范畴。
2. 曲面体曲面体是由曲面上的点组成的三维形状,通常具有自我交叉或曲率的特性。
例如,圆锥体、圆盘、椭球体等都属于曲面体的范畴。
3. 多面体多面体是由多个平面共面的多边形围成的三维形体。
根据多边形的形状和数量的不同,多面体可以进一步分为正多面体和非正多面体两类。
正多面体包括四面体、六面体、八面体等;非正多面体包括棱柱、棱锥、凯利多面体等。
4. 不规则体不规则体是指在三维空间中形状不规则、无法用已知的几何形体描述的三维体。
例如,破碎的岩石、树木的枝干等都属于不规则体。
二、特性除了不同的形态分类外,三维形还具有一些共同的特性,包括以下几个方面:1. 空间定位三维形通过坐标系来描述其在三维空间中的位置。
常用的坐标系包括笛卡尔坐标系、柱坐标系和球坐标系等。
通过坐标系,我们可以准确地定位和描述三维形在空间中的位置。
2. 体积和表面积三维形的体积是指其所占据的空间大小,而表面积则是指三维形的外部皮肤面积。
计算三维形的体积和表面积是数学和物理学中的重要内容,对于工程建设和科学研究都具有重要意义。
3. 对称性三维形可能具有各种不同的对称性,例如平面对称、旋转对称和反演对称等。
这些对称性反映了三维形的内在结构和性质,对于研究其几何形态和应用具有重要的启示作用。
4. 运动和变形三维形在空间中可以进行各种运动和变形。
例如,平移、旋转、缩放等都是常见的三维形的变换操作。
研究三维形的运动和变形可以帮助我们理解其形态演化和应用于实际场景的可能性。
pv3d基础学习学习几何体一pv3d提供几种基本体:平面(Plane)球体(Sphere)圆柱体(Cylinder)圆锥体(Cone)立方体(Cube)箭头(Arrow)纸飞机(PaperPlane)<1>、平面(Plane)plane=newPlane(material:MaterialObject3D,width:Number,height:Number,segmentsW:Number,segmentH :Number)注释:material :null 应用到plane的材质width :0 设置plane的widthheight :0 设置plane的heightsegmentsW :0 设置水平段的数量segmentsH :0 设置竖直段的数量实例:package {import org.papervision3d.view.BasicViewimport org.papervision3d.objects.primitives.Planeimport flash.events.*public class main extends BasicView {//继承BasicView场景private var plane:Planepublic function main(){// constructor codeinit()//初始化startRendering()//3d渲染通道}private function init():void{plane=new Plane(null,300,300,1,1)plane.x=200plane.y=200plane.z=200plane.material.doubleSided=truescene.addChild(plane)}override protected function onRenderTick(e:Event=null):void{plane.localRotationY++super.onRenderTick()}}}//Papervision3D中,增加y坐标使plane向上移动,增加z使plane远离我们,增加x坐标Flash一样将向右移动plane//localRotationX,localRotationY,localRotationZ属性会对象沿着自己的x,y,z轴旋转//平面仅有一面有线框材质,线框是基本体的默认材质当指定材质时便用线框,显示双面材质的一种方式是设置plane的meterial属性,将doubleSider属性设置为true<2>、球面(Sphere)sphere=newSphere(material:MaterialObject3D,radius:Number,segme ntsW:Number,segmentH:Number)注释:material :null 应用到球面的材质radius :100 设置球面的半径segmentsW :8 设置水平段的数量segmentsH :0 设置竖直段的数量参数大部分如上<3>、圆柱(Cylinder)cylinder=new Cylinder(material:MaterialObject3D,radius:Number,height:Number,segmentsW:Number,segmentH:Nu mber,topRadius:Number,topFace:Boolean,bottomFace:Boolean)注释:material :null 应用到圆柱体的材质radius :100 设置圆柱体的半径height :100 设置圆柱体的高segmentsW :8 设置水平段的数量segmentsH :6 设置竖直段的数量topRadius :-1 设置圆柱体的上表面,允许创建圆台,默认值是-1,使上半径与下半径相同topFace :true 上表面是否创建bottomFace :true 下表面是否创建参数大部分如上<4>、圆锥(Cone)cone=newCone(material:MaterialObject3D,radius:Number,height:Number,segmentsW:Number,segmentH :Number)注释:}}三访问顶点3D对象的基本要素-顶点,每个3D对象的顶点都存放在一个数组中,可以通过属性geometry 进行访问。
立体形基本知识点归纳总结立体形,也称为立体几何,是数学中研究三维空间中形状和大小的分支。
它包括了点、线、面以及由它们构成的立体图形。
立体形的基本知识点可以归纳为以下几个方面:### 1. 点(Point)点是立体形中最基本的元素,没有大小,只有位置。
在三维空间中,一个点可以由三个坐标值来确定。
### 2. 线(Line)线是由无数点组成的一维对象。
在三维空间中,直线可以由两个点来确定,或者由一个点和一个方向向量来确定。
### 3. 面(Plane)面是二维的平面区域,由无数的线组成。
在三维空间中,一个平面可以由三个不共线的点来确定,或者由一个点和一个法向量来确定。
### 4. 体积(Volume)体积是立体形的三维度量,表示一个立体图形所占据的空间大小。
常见的立体形包括立方体、球体、圆柱体等。
### 5. 立体图形(Solid Figures)立体图形是由面和体积构成的三维对象。
它们可以是规则的,如正方体、球体;也可以是不规则的,如多面体。
### 6. 空间关系(Spatial Relationships)立体形的空间关系包括相交、平行、垂直等。
这些关系可以通过点、线、面之间的相对位置和方向来判断。
### 7. 立体图形的测量(Measurement of Solid Figures)立体图形的测量包括长度、面积、体积等。
例如,立方体的体积是其边长的三次方,球体的体积是 \( \frac{4}{3} \pi r^3 \),其中\( r \) 是球体的半径。
### 8. 立体图形的变换(Transforms)立体图形可以通过平移、旋转、缩放等变换来改变其位置、方向或大小。
### 9. 立体图形的对称性(Symmetry)对称性是立体图形的一个重要特性,包括反射对称、旋转对称等。
对称性可以帮助我们更好地理解和描述立体图形。
### 10. 立体图形的构造(Construction of Solid Figures)立体图形可以通过组合基本的几何形状来构造更复杂的立体图形。
基本几何体如果你熟悉Maya,3DstudioMax,或CINEMA4d等建模软件,会发现软件里往往有一些内臵的基本形体.基本体是一些基本的几何图形如平面,球体,立方体.大多数建模软件通过单击拖拽等操作就可以创建出基本体,或修改它.当然也可以自己建,但3d建模软件里的基本体为建模者提供了一种捷径.Papervision3D也包含一些基本形体.Papervision3D没有图形界面不能通过点击拖拽等操作来创建几何体.但在程序里却可以随时方便的使用它们.修改Papervision3D里的几何体比3D建模软件中困难的多,还是因为没有图形界面.然而使用更加复杂的模型是可能的,Papervision3D允许你将建模软件中创建的模型导入到应用中.第8章我们将细看下从3d软件中导出模型和将模型导入到工程.本章,我们首先花些时间来加深对定点和三角面的理解—每个3d对象的基本元素.接着,我们将认识下每一个基本几何体,尝试下如何创建并将其加入到场景中.并将探讨怎样将子对象加入到父对象而不是直接加入到场景.最后,我们将完成一个包含所探讨对象的例子程序.本章包含:●3d几何体详解●Papervision3D如何将3d信息转入到2d屏幕●创建并添加基本形体●3d对象的嵌套在创建形体之前,我们将仔细下3d对象的组成.同时将简单的探讨下转换3d对象到2d图形的处理过程,称其为渲染管道.3d对象的基本元素日常生活中不难想象3维,而且我们一直都是3维世界的一部分.在计算机的屏幕上,3d是不同的因为屏幕只是2d的.现在通过图解来熟悉下2d屏幕里的第三维.顶点3d几何中,每个形体都由一组顶点(vertices)组成,常称作verts(单数:vertex),顶点是3d 空间的一个点.在Flash中定义sprite的位臵时,设臵2个轴(x,y).顶点有三个坐标,设臵z轴.3d 坐标的顺序为(x,y,z.)三角面顶点形成三角形,称做:面,或三角面,每个三角面有3个顶点组成.一些3d 程序有时允许创建一个有4个顶点组成的面,称做:四角面,但Papervision3D 只能识别三角面.因为顶点通过(x,y,z)坐标确定了三角面的形状并可以三角面面向任何方向.当你绘制多个三角面并将它们依次摆放到3d 空间时,你便可以创造出任何形状.Papervision3D 中图形都涉及到三角形网格.通过三角形网格创建3d 对象.下图显示了用上图的三角网格组成的形体,不过我们将其中的一个旋转了90度.虽然所有的顶点和三角形都是绘制在2d 屏幕上,但却可以在屏幕上看到3d 对象的宽度,高度和深度.通过设臵顶点x,y,z 的坐标,Papervision3D 便知如何在2d 屏幕上创建它们以便产生3d 的视觉.换句话说,Papervision3D 知道如何在2d 空间中表示3d 形体.Papervision3D 类库中,类Vertices3D 负责创建顶点,TriangleMesh3D 类负责创建由顶点和三角面组成的3d 对象.如我们所见,用这些可很容易创建出基本体.当顶点确定了对象的形状时,三角面则是材质的轮廓,可以是简单颜色或位图甚至视频.Papervision3D 包含了各种各样的材质类,可用其创建有趣并真实的物体.前面已经涉及到了材质,但只是简单的使用了线框和颜色等基础材质.(第4章通篇讲解如何使用材质).渲染管道顶点三角面三角网格如果你熟悉3d 建模,可能会对Papervision3D 里的多边形规则感到惊讶.大多数建模软件多边形被定义成面,至少有4个角由2个或多个三角形组合而成,Papervision3D 不能识别这样的多边形,也不含有Polygon 类.实际上Papervision3D 仅支持三角面或三角多边形.发布工程,为了让2d屏幕出现3d视觉,Papervision3D还需要处理几个过程.将3d信息转换到2d屏幕,这个过程的顺序称为:渲染管道(rendering pipeline).Papervision3D的渲染管道为:初始化→投影→渲染前节中当构建好第一个应用,初始完一个球体发布后便会在屏幕上显示.现在用球体的例子说明下渲染管道.初始化这部分完成视角(viewport),场景(scene),摄影机(camera),渲染引擎(renderer)和3d对象的创建.某些对象只须创建一次.第2章在init()中创建的有默认线框材质的球体就是标准的初始化.投影将3d坐标转换到2d屏幕上.前面说过,3d对象由顶点组成,每个顶点有3个坐标.2d 的屏幕仅有x轴和y轴,不能简单的将3d对象匹配到2d屏幕上.Papervision3D获取到每个顶点的3d坐标并将它们投影到2d平面上,计算出在屏幕上每个顶点所处的位臵.投影的过程只处理顶点,不处理三角面和材质.在球体的例子中,Papervision3D获取球体的3d顶点,每次渲染时进行如何投影到2d屏幕上的计算工作.渲染在屏幕绘制出图形的过程.此过程用附着的材质信息组成2d投影数据.此过程使用Flash图形API的lineTo()方法绘制三角形.为了添加材质,使用了Flash图形API的beginBitmapFill()方法.材质通常是BitmapData对象,填充到三角形后往往会被缩放及扭曲.渲染部分不识别3d坐标.只对2d的投影感兴趣.到目前为止这部分最耗处理器.创建并添加基本形体Papervision3D提供了以下几种基本体:●平面(Plane)●球体(Sphere)●圆柱体(Cylinder)●圆锥体(Cone)●立方体(Cube)●箭头(Arrow)●纸飞机(PaperPlane)箭头和纸飞机的形状比其余的对象的形状稍微特殊,可能在现实应用中经常使用.从Papervision3D 库刚开始时,纸飞机便是本库中的一部分,目的是为开发者提供一种用来执行全面测试的简单对象.另一方面,纸飞机与多数3d 建模软件里面的犹他茶壶(Utah teapot)的作用类似.Papervision3D 里的基本形体很容易使用.我们将通过例子来说明每个基本体如何创建并如何加入到场景中.在第2章我们写过一个模板类,所以不必一遍一遍的写基本的代码.我们已经知道了如何以模板为基础开始新工程,每当你准备动手敲一遍本书的代码时都可以这样做.可以在Fla 中处理并调用你的第一个PlaneExample 例子程序.如果用的是flex,flashbuilder 通常是一个ActionScript 工程伴随一个同名的文档类在文档类中调用.现在我们来看一下第一个基本体:PlanePlane平面是基本体中最简单的形体.如果你不旋转它,它看起来就是一个2d 矩形.只需要将其引入,创建后加入到场景即可.前面已经建立了一个PlaneExample,现在只需要加入几行代码.package {import flash.events.Event;import org.papervision3d.view.BasicView;import org.papervision3d.objects.primitives.Plane; public class PlaneExample extends BasicView {private var plane:Plane;public function PlaneExample() {stage.frameRate = 40;犹他州茶壶是一种3d 模型,Martin Newell,1975年在妻子Sandra 为他们的茶服务建立模型的建议下创建的.众所周知对于快速测试非常有用.原始的茶壶模型现在陈列在加拿大计算机历史博物馆中init();startRendering();}private function init():void{plane = new Plane(null,300,300,1,1);scene.addChild(plane);}override protected function onRenderTick (e:Event=null):void{super.onRenderTick();}}}为了创建一个平面我们添加了什么代码?为了使用Plane类及属性方法,首先需要导入它.所有的基本几何体位于包org.papervision3d.objects.primitives.之后为Plane实例变量指定变量plane.使其作为类属性,不是局部变量,以确保其在构造器外可以进行访问如render方法.之后,通过传递一些参数到Plane构造器来创建一个Plane并使用addChild()将其添加到场景中.如果我们发布此例子,应该可以看到有2个三角面组成的简单plane.现在看一下,我们传递到Plane构造器的5个参数:参数数据类型默认值说明1 material MaterialObject3D null 应用到plane的材质2 width Number 0 设臵plane的width3 height Number 0 设臵plane的height4 segmentsW Number 0 设臵水平段的数量5 SegmentsH Number 0 设臵竖直段的数量例子中material为null,将应用默认的线框材质WireframeMaterial.第5,6个参数定义了段的数量.用下图来说明:左侧的plane有一个宽度段和一个高度段.中间的有2个宽度段和一个高度段.右侧的plane有2个宽度和2个高度段.正如所见,每增加一个宽度或高度段会多2个三角面片.虽然段数默认值为0,传递0或不传递值将使plane 宽度和高度段都为1.传递width 和height 的值为0或无值,plane 的宽高将为500*500单元;现在我们已经看到了传递到Plane 构造器的那些参数,接着看一下plane 创建好之后可以使用的属性.所有的基本几何体都间接的继承了DisplayObject3D.换句话说,基本几何体继承了DisplayObject3D 的所有非private 的属性.现在看一下plane 继承过来的定位属性,在PlaneExample 的init 方法中设置x,y,z:private function init():void {plane = new Plane(null,300,300,1,1); scene.addChild(plane); plane.x = 200; plane.y = 200; plane.z = 300; }第2章,我们讨论过Flash 和Papervision3D 坐标系的差异.在Papervision3D 中,增加y 坐标使plane 向上移动,增加z 使plane 远离我们.增加x 坐标与Flash 一样将-向右移动plane.在渲染场景的方法内,我们添加另一个属性,localRotationY,并且我们在每一帧将其值增加1.override protected function onRenderTick(e:Event=null):void {plane.localRotationY++; super.onRenderTick(); }这会使plane 绕自身y 轴进行旋转.正如所见一些属性与ActionScript 中的DisplayObject 类很类似,如x 和y.但Papervision3D 的DisplayObject3D 有一组额外的属性(和方法)允许实例在3D 空间中移动和旋转如z 和localRotationY.在plane 上附着一个图片,有一个常见的问题,当旋转plane 时图片会被扭曲.可以通过增加段的数量来避免此问题.增加段数的同时也必须加倍小心.增加的段数越多,需要消耗更多的渲染能力.太多的三角面片会导致Flash player 很难控制此对象.通常来说整个场景的段数总数最好在3000以下.与Flash 的影片剪辑相同,每一个基本体有一个注册点.影片剪辑的注册点默认是(0,0),3D 对象是(0,0,0),定位在场景中心或对象原点.然而在影片剪辑中注册点是可以改变的,但Papervision3D 对象的注册点不能轻易变更.如果现在发布工程将看到一个正在旋转的平面,但是,此平面仅有一面有线框(wireframe)材质.线框是基本体的默认材质当不指定材质时便用线框.显示双面材质的一种方式是设臵plane的meterial属性,将doubleSided属性设为true.plane.material.doubleSided = true;将其加入到init()方法的plane初始化后,会让平面的双面都有材质.球体Sphere前面已经创建过球体.为了保持前后一致,我们将BasicViewExample的代码粘贴到SphereExample的文档类中,注意同时修改类与构造器的定义.代码如下:package {import flash.events.Event;import org.papervision3d.objects.primitives.Sphere;import org.papervision3d.view.BasicView;public class SphereExample extends BasicView{private var sphere:Sphere;public function SphereExample (){init();startRendering();}这里有一些旋转Papervision3D中的对象方式.localRotationX,localRotationY,localRotaionZ属性会对象沿着自己的x,y,z轴旋转.这些值为角度,如plane.localRotationY = 45将使plane绕自身y轴旋转45度.细看DisplayObject3DPapervision3D文档这样描述DisplayObject3D:DisplayObject3D类代表了在场景中的3D对象的实例听起来在3D场景中没有比它更值得关注的了.你可以说DisplayObject3D对象实际上是虚的,有很多子类.不止基本体是DisplayObject3D的子类,Camera类和DAE(载入外部模块到Papervision3D中)类也是,DisplayObject3D有一些关键的属性和方法,可被3D对象使用的.从本章起整本书都在讨论这些属性和方法.随着收到邮件的增多,Papervision3D社区接纳了do3D,这是3d显示对象的缩写.这不止引用了一个DisplayObject3D的实例也代表了一个DisplayObject3D子类的实例.因此,一个Plane类的实例不但可以说是一个Plane类的实例同时是一个do3D.private function init():void{sphere = new Sphere();scene.addChild(sphere);}override protected function onRenderTick(e:Event=null):void{sphere.localRotationY--;super.onRenderTick();}}}我们实例化的球体只有外边有材质.记住不传递任何材质与传递null一样-都将使用线框材质.让我们详细看下Sphere有参构造.改变init()中的这行:sphere = new Sphere();为sphere = new Sphere(null,300,16,12);如果你想知道可以给Sphere构造器(或其他基本体的构造器)传递什么参数,可以参考下文档. 查找Sphere类然后查看构造器细节.将会看到这行:public function Sphere(material:MaterialObject3D = null, radius:Number= 100, segmentsW:int = 8, segmentsH:int = 6)这是Sphere构造器的第一部分.显示了实例化球体可用的参数.下面的表格进行说明:参数数据类型默认值说明1 material MaterialObject3D Null 定义附加到球体表面的材质2 radius Number 100 设臵球体半径(球体中心与顶点的距离)3 segmentsW Number 8 设臵水平段数量4 segmentsH Number 6 设臵竖直段数量花点时间来练习使用这些值.需要注意的是增加段的数量会降低对象移动的平滑度.原因是越多的段数,将会创建更多的顶点和三角面片,Flashplayer渲染起来就越费劲.圆柱Cylinder创建一个圆柱体并将其加入到场景中跟之前的平面与球体类似.如果你准备继续动手的话,我们将继续创建工程和文档类,命名为CylinderExample.导入Cylinder类:import org.papervision3d.objects.primitives.Cylinder;在init()中我们实例化基本体并赋值给局部变量.之后将圆柱体添加到场景中.private function init():void{var cylinder:Cylinder = new Cylinder(null,80,400,8,2,-1,false,true);scene.addChild(cylinder);}发布之后将看到圆柱体Cylinder 构造器有8个参数可以传递参数 数据类型默认值 说明1 material MaterialObject3D null 设臵圆柱体的材质2 radius Number 100 圆柱体的半径3 height Number 100 圆柱体的高4 segmentsW Number 8 圆柱体水平段数5 segmentsH Number6 圆柱体竖直段数 6topRadiusNumber-1设臵圆柱体的上表面.允许创建圆台.默认值是-1使上半径与下半径相同 7 topFace Boolean True 上表面是否创建 8bottomFaceBooleanTrue下表面是否创建同时设定topFace 与bottomFace 为false,将创建一个没有上底与下底,像一个管子:圆锥体Cone你可能已经注意到了,初始化基本体的关键字都是统一的.惯例.我们从创建一个新工程开始,这时我们会将工程命名为ConeExample.导入Cone 类. import org.papervision3d.objects.primitives.Cone;我们在init()中实例化cone 并传递null 的材质和其他的4个参数,将实例加入到场景. private function init():void {var cone:Cone = new Cone(null,150,400,8,4);牢记.当在方法内使用局部变量实例化对象时,不能在方法外进行访问.如果想在onRenderTick()方法内操作对象如旋转,只能将实例指定为类的属性.scene.addChild(cone);}Cone构造器可用的参数参数数据类型默认值说明1 material MaterialObject3D Null 圆锥的材质2 radius Number 100 圆锥的半径3 height Number 100 圆锥的高4 segmentsW Number 8 水平段数量5 segmentsH Number6 竖直段数量圆锥的顶部都是尖的,只能改变圆锥的底半径.立方体Cube前面的章节我们已经创建过一个平面, 一个球体, 一个圆柱体和一个圆锥体.在这些例子中我们都传递了null作为材质参数,导致基本体使用默认的线框材质.虽然初始化立方体跟初始化前面的基本体很类似,但附着材质的方式却有很大的不同.Cube的构造器第一个参数不是材质,是材质列表(materials list).立方体有6个面,通过将材质加入到材质列表,可以为每个面附着上不同的材质.创建材质列表需要导入类MaterialList.同时也导入类Cube,这次我们将使用颜色作为材质,因此还需要导入类ColorMaterial.import org.papervision3d.materials.utils.MaterialsList;import org.papervision3d.materials.ColorMaterial;import org.papervision3d.objects.primitives.Cube;创建一个类的属性:private var cube:Cube;在init()方法中,我们首先创建一个颜色材质,传递16进制颜色值到ColorMaterial的构造器:private function init():void{var red:ColorMaterial = new ColorMaterial(0xFF0000);var blue:ColorMaterial = new ColorMaterial(0x0000FF);var green:ColorMaterial = new ColorMaterial(0x00FF00);现在初始化材质列表.var materialsList:MaterialsList = new MaterialsList();现在我们使用addMaterial()方法将材质加入到材质列表.我们将每个颜色材质附着到立方体相反的2面.materialsList.addMaterial(red,"front");materialsList.addMaterial(red,"back");materialsList.addMaterial(blue,"left");materialsList.addMaterial(blue,"right");materialsList.addMaterial(green,"top");materialsList.addMaterial(green,"bottom");注意下此方法传递的第二个参数如"front"和"back".这个参数是字符串,表示立方体的面.本章之前我们所指的面是另一个词:triangles 三角面片.而当我们提到立方体的面是我们指的的是6个面,而非三角面片.最后,使用材质列表和其余的三个参数来初始化立方体,并将其添加到场景中.cube = new Cube(materialsList,300,300,300);scene.addChild(cube);}现在总结一下Cube 类所使用的参数:参数名 数据类型 默认值 说明 1materials MaterialList 包含显示对象材质属性的列表 2width Number 500 指定宽度 3depth Number 500 指定深度 4height Number 1 指定高度 5segmentsS int 1 宽度段的数量 6segmentsT int 1 高度段的数量 7segmentsH int 1 深度段的数量 8insideFaces int 0 指定立方体内部可见的面数 9 excludeFaces int0 指定不创建的面 参数5,6,7指定段的数量.下图的3个立方体显示了每个参数如何将有1个段的面细分成有2个段的面:当上面的立方体被初始化时,参数5,6,7被赋值为下面的值:● 左,立方体:2,1,1,将与x 轴平行的面划分成2面,(宽度段)● 中,立方体:1,2,1, 将与y 轴平行的面划分成2面,(高度段)● 右,立方体:1,1,2, 将与z 轴平行的面划分成2面,(深度段)下面解释下参数8,9,例子中并没传递.参数insideFaces 指定立方体内部可见的面.假设你的摄影机被放臵到立方体的内部并且你只想显示立方体的后边的面.可以通过传递Cube.BACK 来达成此目的.当传递参数时,可以加减(+,-)相应的面,如传递Cube.ALL-CUBE.LEFT 将显示全部的面除了左边的面.参数excludeFaces 指定不创建的面.这里也可以进行加减(+,-).传递Cube.FRONT+Cube.BACK,创建的立方体将没有前面与后面.如果你想让6个面附着相同的材质,可以给addMaterial()传递字符串'all':materialsList.addMaterial( green,"all");由于cube 是一个类属性,可以在渲染的方法中访问它.让我们让立方体绕3轴进行旋转,借以看到全部外部的面:override protected function onRenderTick(e:Event=null):void{cube.localRotationX++;cube.localRotationY++;cube.localRotationZ++;super.onRenderTick();}纸飞机PaperPlane在本章的介绍中,我们看到,Pavervision3D 项目的纸飞机主要用于测试.为什么纸飞机适合作为一个测试对象,是它特殊的外观-让我们可以清楚的看到它指向的方向及它旋转的方向. 当创建一个3d 物体移动和旋转的应用时可以用它方便的进行测试.假设在场景中有一个线框材质的球体并准备让球体旋转270度.当球体旋转快完成时,很难知道球体正面所面向的方向是否是你所期望的方向.临时将球体替换成纸飞机可以让你更容易的看清物体的运行情况,因为可以清楚的看到纸飞机的位臵和旋转.用之前,须导入类PaperPlane.import org.papervision3d.objects.primitives.PaperPlane;类PaperPlane 的构造器需要2个参数-材质和缩放.下面我们初始化一个放大了3倍的纸飞机,并将其加入到场景中:var paperPlane:PaperPlane = new PaperPlane(null,3);scene.addChild(paperPlane);纸飞机的构造器没有可用的宽度,深度和高度参数,文档中也没有列出相应的默认值. 但如果你需要知道这些值,以便将物体缩放到需要尺寸?我们应该明白:很多时候我们不知道或不能快速访问3d 对象的尺寸,如已被随机指定的值.但可以这样来获取.......注意参数列表中insideFaces 和excludeFaces 的默认值都是0,这也等于是Cube.NONE;下面演示了一个绕自身x 轴旋转90的纸飞机:箭头 Arrow虽然不是不能想象,箭头可能不是你工程中的基本体.但就像纸飞机,箭头也是作为一个方便测试服务的对象,它也可以给你一个明确的方向感.现在你可以在想如何导入此类呢? 如此:import org.papervision3d.objects.primitives.Arrow;箭头的构造器只有一个材质的参数,无参的箭头这样创建:var arrow:Arrow = new Arrow();scene.addChild(arrow);跟以往一样,不传递材质将使用线框材质.与PaperPlane 类似,Arrow 的构造也没可用的尺寸参数.默认值是宽400,高100,深600.如果要改变箭头的尺寸,可使用从DisplayObject3D 对象继承的scale 属性:arrow.scale = 0.5;获取3d 对象的尺寸类Vertices3D.boundingBox()方法计算3d 对象内接长方体并可以获取任意继承自Vertices3D,Papervision3D 内置的,可以在屏幕上显示的3d 对象的宽度,深度和高度.内接长方体刚好将3d 对象容纳其中.下图展示了纸飞机和内接长方体:获取物体内接长方体的尺寸: trace(paperPlane.boundingBox().size); 属性size 返回3个数字代表了对象的顶点在各轴上不同的位置.调用trace 后输出: x:100 y:33.33z::200 表示x,y,z 方向的尺寸.由此可见纸飞机有一个默认的宽度100,默认的高度33.33,和默认的深度200.也可以单独获取每维上的尺寸.下面只输出宽度: trace(paperPlane.boundingBox().size.x); 因此,如果想让纸飞机的宽度为200单元,应该将缩放因子设为2.再者纸飞机继承自DisplayObject3D,可以使用scaleX 和scaleY 来单独设置x 和y 方向的缩放.下图显示了绕自身x轴旋转45度的箭头:嵌套Nesting嵌套是一种将1个或多个对象加入嵌入到一个父对象中的技术.嵌套的好处是你可以创建一个子对象行为与父对象行为有关的层次结构.如可以组织一组对象将他们嵌入到一个父对象中并组织另一组对象嵌入到另一个父对象中.这可以使你按组来控制这些对象.前面的例子中,每当我们创建一个基本体我们直接调用addChild()方法将其添加到场景中.但不只Scene3D对象有这个方法,DisplayObject3D也有.我们看一下类的继承关系:●DisplayObject3D 继承自DisplayObjectContainer3D●Scene3D继承自SceneObject3D,SceneObject3D继承自DisplayObjectContainer3DScene3D和DisplayObject3D都从DisplayObjectContainer3D中继承了addChild()方法.这表示我们也可以在基本体上使用addChild()方法,因为它们继承了DisplayObject3D的属性和方法.现在我们创建一个球嵌套球的工程,命名为NestingExample,之后导入Sphere,将大球体指定为类的属性.private var parentSphere:Sphere;在init()方法中我们先创建一个父球体并将其加入到场景中.private function init():void{parentSphere = new Sphere(null,200,16,12);scene.addChild(parentSphere);接着我们使用局部变量创建一个子球体并将x坐标指定为400.var childSphere:Sphere = new Sphere(null,100,12,8);childSphere.x = 400;现在我们将子球体添加到父球体中而非直接添加到场景.子球体的x为400.我们没指定父球体的坐标,所以它的坐标是场景的原点(0,0,0).现在让我们认识下子球体嵌入到父球体后的坐标系.世界空间vs 本地空间将子球体加入父球体这一刻,子球体的坐标便是与父球体有关的本地坐标.而与全局场景坐标系无关.我们称全局坐标系(与场景有关的坐标系)为世界空间并称本地坐标系为本地空间.因此,每当将DisplayObject3D的实例嵌入时,它便有一个本地坐标.与2D Flash进行比较,在Flash中也可嵌入对象.如可以将一个影片剪辑(MovieClip)嵌入到另一个影片剪辑.假如你将子剪辑嵌入到父剪辑则子剪辑的坐标便于父剪辑的位臵有关.子剪辑将与父剪辑一起被移动和转动.同样,缩放父剪辑同时会缩放子剪辑.现在继续写我们的NestingExample类并在onRenderTick()方法中增加属性localRotationY的值让父球体绕自身y轴旋转:override protected function onRenderTick(e:Event=null):void{parentSphere.localRotationY++;super.onRenderTick();}当发布这个例子时可以看到父球体正绕自身y轴旋转.虽然没让子球体转动,但它也在转.父球体处于世界坐标而非本地坐标.子球体随父球体一起移动因为它的坐标系与父球体有关.如果在渲染方法中输出子球体的x坐标,其值一直是400,因为它并没在本地坐标中移动.当你使用嵌套时必须牢记这个原则.如果你想知道子球体的场景坐标(世界坐标),可以使用属性sceneX.在渲染方法中调用trace(childSphere.sceneX)将持续输出400到-400之间的值.DisplayObject3D也有sceneY和sceneZ属性.下图是正在旋转父球体.注意子球体的x值一直是400而sceneX一直在变化.将3d对象嵌入到其他的3d对象中很明显有重大的好处.可以将多个对象嵌入到一个父对象中然后控制父对象,如从一点移动到另一点.因为每个子对象的坐标都与父对象有关,他们将与父对象一起移动.因此,可用来替代单独通知每个要移动的对象,通知父对象进行移动则所有的子对象都会移动.用DisplayObject3D创建一个基本点常用的嵌套技术是创建一个DisplayObject3D的实例作为其他对象的容器(如基本体).这与前节中类似.但是,这时父对象不是基本体,而是DisplayObject3D的实例.如果你创建一个do3D(译注:DisplayObject3D)并将其加入到场景,将发现在场景无法看到它,因为它不是由顶点和三角面片组成.然而与基本体类似它有addChild()方法表明它可以容纳其他的对象.同时do3D也有全部的移动和转动的属性和方法.do3D将作为子对象的一个基本点(像前节中的父球体那样).要访问类DisplayObject3D需要先导入.import org.papervision3d.objects.DisplayObject3D;下面的代码显示了部分类PivotDO3DExample.注意与前节的类NestingExample很类似.此时我们将DisplayObject3D的实例指定为类属性.private var pivotDO3D:DisplayObject3D;在init()方法中我们创建do3D并将其加入到场景.private function init():void{pivotDO3D = new DisplayObject3D();scene.addChild(pivotDO3D);接着,我们创建子球体并将其x坐标设为400.var childSphere:Sphere = new Sphere(null,100,12,8);childSphere.x = 400;将子球体加入到do3D中:pivotDO3D.addChild(childSphere);}在渲染方法中我们让父对象绕自身y轴旋转.override protected function onRenderTick(e:Event=null):void{pivotDO3D.localRotationY++;super.onRenderTick();}如果你将此类与NestingExample进行比较你会发现我们只是将parentSphere换成了DisplayObject3D的实例:pivotDO3D.将子对象加入到pivotDO3D使子对象的坐标系与它有关.这时发布后会发现球体绕pivotDO3D这个虚拟点旋转,这正如NestingExample 中子球体同父球体一起移动相同.访问顶点现在我们复习一下3D对象的基本要素-顶点.每个3D对象的顶点都存放在一个数组中.可以通过属性geometry进行访问.do3D.geometry.vertices假设你想知道类PlaneExample的平面中所有顶点的x,y坐标.因为顶点存放在数组中,可以使用length属性查看有多少个.var numberOfVertices = plane.geometry.vertices.length;此时可以通过for循环遍历.for(var i:uint = 0; i < numberOfVertices; i++){trace("x: " + plane.geometry.vertices[i].x,"y: " + plane.geometry.vertices[i].y,"z: " + plane.geometry.vertices[i].z)}输出:x: -150 y: -150 z: 0x: -150 y: 150 z: 0x: 150 y: -150 z: 0x: 150 y: 150 z: 0如你所见,只输出了4个点的x,y,z.你可以会认为是6个点,因为每个三角行有3个点而现在。
基本几何体如果你熟悉Maya,3DstudioMax,或CINEMA4d等建模软件,会发现软件里往往有一些内臵的基本形体.基本体是一些基本的几何图形如平面,球体,立方体.大多数建模软件通过单击拖拽等操作就可以创建出基本体,或修改它.当然也可以自己建,但3d建模软件里的基本体为建模者提供了一种捷径.Papervision3D也包含一些基本形体.Papervision3D没有图形界面不能通过点击拖拽等操作来创建几何体.但在程序里却可以随时方便的使用它们.修改Papervision3D里的几何体比3D建模软件中困难的多,还是因为没有图形界面.然而使用更加复杂的模型是可能的,Papervision3D允许你将建模软件中创建的模型导入到应用中.第8章我们将细看下从3d软件中导出模型和将模型导入到工程.本章,我们首先花些时间来加深对定点和三角面的理解—每个3d对象的基本元素.接着,我们将认识下每一个基本几何体,尝试下如何创建并将其加入到场景中.并将探讨怎样将子对象加入到父对象而不是直接加入到场景.最后,我们将完成一个包含所探讨对象的例子程序.本章包含:●3d几何体详解●Papervision3D如何将3d信息转入到2d屏幕●创建并添加基本形体●3d对象的嵌套在创建形体之前,我们将仔细下3d对象的组成.同时将简单的探讨下转换3d对象到2d图形的处理过程,称其为渲染管道.3d对象的基本元素日常生活中不难想象3维,而且我们一直都是3维世界的一部分.在计算机的屏幕上,3d是不同的因为屏幕只是2d的.现在通过图解来熟悉下2d屏幕里的第三维.顶点3d几何中,每个形体都由一组顶点(vertices)组成,常称作verts(单数:vertex),顶点是3d 空间的一个点.在Flash中定义sprite的位臵时,设臵2个轴(x,y).顶点有三个坐标,设臵z轴.3d 坐标的顺序为(x,y,z.)三角面顶点形成三角形,称做:面,或三角面,每个三角面有3个顶点组成.一些3d 程序有时允许创建一个有4个顶点组成的面,称做:四角面,但Papervision3D 只能识别三角面.因为顶点通过(x,y,z)坐标确定了三角面的形状并可以三角面面向任何方向.当你绘制多个三角面并将它们依次摆放到3d 空间时,你便可以创造出任何形状.Papervision3D 中图形都涉及到三角形网格.通过三角形网格创建3d 对象.下图显示了用上图的三角网格组成的形体,不过我们将其中的一个旋转了90度.虽然所有的顶点和三角形都是绘制在2d 屏幕上,但却可以在屏幕上看到3d 对象的宽度,高度和深度.通过设臵顶点x,y,z 的坐标,Papervision3D 便知如何在2d 屏幕上创建它们以便产生3d 的视觉.换句话说,Papervision3D 知道如何在2d 空间中表示3d 形体.Papervision3D 类库中,类Vertices3D 负责创建顶点,TriangleMesh3D 类负责创建由顶点和三角面组成的3d 对象.如我们所见,用这些可很容易创建出基本体.当顶点确定了对象的形状时,三角面则是材质的轮廓,可以是简单颜色或位图甚至视频.Papervision3D 包含了各种各样的材质类,可用其创建有趣并真实的物体.前面已经涉及到了材质,但只是简单的使用了线框和颜色等基础材质.(第4章通篇讲解如何使用材质).渲染管道顶点三角面三角网格如果你熟悉3d 建模,可能会对Papervision3D 里的多边形规则感到惊讶.大多数建模软件多边形被定义成面,至少有4个角由2个或多个三角形组合而成,Papervision3D 不能识别这样的多边形,也不含有Polygon 类.实际上Papervision3D 仅支持三角面或三角多边形.发布工程,为了让2d屏幕出现3d视觉,Papervision3D还需要处理几个过程.将3d信息转换到2d屏幕,这个过程的顺序称为:渲染管道(rendering pipeline).Papervision3D的渲染管道为:初始化→投影→渲染前节中当构建好第一个应用,初始完一个球体发布后便会在屏幕上显示.现在用球体的例子说明下渲染管道.初始化这部分完成视角(viewport),场景(scene),摄影机(camera),渲染引擎(renderer)和3d对象的创建.某些对象只须创建一次.第2章在init()中创建的有默认线框材质的球体就是标准的初始化.投影将3d坐标转换到2d屏幕上.前面说过,3d对象由顶点组成,每个顶点有3个坐标.2d 的屏幕仅有x轴和y轴,不能简单的将3d对象匹配到2d屏幕上.Papervision3D获取到每个顶点的3d坐标并将它们投影到2d平面上,计算出在屏幕上每个顶点所处的位臵.投影的过程只处理顶点,不处理三角面和材质.在球体的例子中,Papervision3D获取球体的3d顶点,每次渲染时进行如何投影到2d屏幕上的计算工作.渲染在屏幕绘制出图形的过程.此过程用附着的材质信息组成2d投影数据.此过程使用Flash图形API的lineTo()方法绘制三角形.为了添加材质,使用了Flash图形API的beginBitmapFill()方法.材质通常是BitmapData对象,填充到三角形后往往会被缩放及扭曲.渲染部分不识别3d坐标.只对2d的投影感兴趣.到目前为止这部分最耗处理器.创建并添加基本形体Papervision3D提供了以下几种基本体:●平面(Plane)●球体(Sphere)●圆柱体(Cylinder)●圆锥体(Cone)●立方体(Cube)●箭头(Arrow)●纸飞机(PaperPlane)箭头和纸飞机的形状比其余的对象的形状稍微特殊,可能在现实应用中经常使用.从Papervision3D 库刚开始时,纸飞机便是本库中的一部分,目的是为开发者提供一种用来执行全面测试的简单对象.另一方面,纸飞机与多数3d 建模软件里面的犹他茶壶(Utah teapot)的作用类似.Papervision3D 里的基本形体很容易使用.我们将通过例子来说明每个基本体如何创建并如何加入到场景中.在第2章我们写过一个模板类,所以不必一遍一遍的写基本的代码.我们已经知道了如何以模板为基础开始新工程,每当你准备动手敲一遍本书的代码时都可以这样做.可以在Fla 中处理并调用你的第一个PlaneExample 例子程序.如果用的是flex,flashbuilder 通常是一个ActionScript 工程伴随一个同名的文档类在文档类中调用.现在我们来看一下第一个基本体:PlanePlane平面是基本体中最简单的形体.如果你不旋转它,它看起来就是一个2d 矩形.只需要将其引入,创建后加入到场景即可.前面已经建立了一个PlaneExample,现在只需要加入几行代码.package {import flash.events.Event;import org.papervision3d.view.BasicView;import org.papervision3d.objects.primitives.Plane; public class PlaneExample extends BasicView {private var plane:Plane;public function PlaneExample() {stage.frameRate = 40;犹他州茶壶是一种3d 模型,Martin Newell,1975年在妻子Sandra 为他们的茶服务建立模型的建议下创建的.众所周知对于快速测试非常有用.原始的茶壶模型现在陈列在加拿大计算机历史博物馆中init();startRendering();}private function init():void{plane = new Plane(null,300,300,1,1);scene.addChild(plane);}override protected function onRenderTick (e:Event=null):void{super.onRenderTick();}}}为了创建一个平面我们添加了什么代码?为了使用Plane类及属性方法,首先需要导入它.所有的基本几何体位于包org.papervision3d.objects.primitives.之后为Plane实例变量指定变量plane.使其作为类属性,不是局部变量,以确保其在构造器外可以进行访问如render方法.之后,通过传递一些参数到Plane构造器来创建一个Plane并使用addChild()将其添加到场景中.如果我们发布此例子,应该可以看到有2个三角面组成的简单plane.现在看一下,我们传递到Plane构造器的5个参数:参数数据类型默认值说明1 material MaterialObject3D null 应用到plane的材质2 width Number 0 设臵plane的width3 height Number 0 设臵plane的height4 segmentsW Number 0 设臵水平段的数量5 SegmentsH Number 0 设臵竖直段的数量例子中material为null,将应用默认的线框材质WireframeMaterial.第5,6个参数定义了段的数量.用下图来说明:左侧的plane有一个宽度段和一个高度段.中间的有2个宽度段和一个高度段.右侧的plane有2个宽度和2个高度段.正如所见,每增加一个宽度或高度段会多2个三角面片.虽然段数默认值为0,传递0或不传递值将使plane 宽度和高度段都为1.传递width 和height 的值为0或无值,plane 的宽高将为500*500单元;现在我们已经看到了传递到Plane 构造器的那些参数,接着看一下plane 创建好之后可以使用的属性.所有的基本几何体都间接的继承了DisplayObject3D.换句话说,基本几何体继承了DisplayObject3D 的所有非private 的属性.现在看一下plane 继承过来的定位属性,在PlaneExample 的init 方法中设置x,y,z:private function init():void {plane = new Plane(null,300,300,1,1); scene.addChild(plane); plane.x = 200; plane.y = 200; plane.z = 300; }第2章,我们讨论过Flash 和Papervision3D 坐标系的差异.在Papervision3D 中,增加y 坐标使plane 向上移动,增加z 使plane 远离我们.增加x 坐标与Flash 一样将-向右移动plane.在渲染场景的方法内,我们添加另一个属性,localRotationY,并且我们在每一帧将其值增加1.override protected function onRenderTick(e:Event=null):void {plane.localRotationY++; super.onRenderTick(); }这会使plane 绕自身y 轴进行旋转.正如所见一些属性与ActionScript 中的DisplayObject 类很类似,如x 和y.但Papervision3D 的DisplayObject3D 有一组额外的属性(和方法)允许实例在3D 空间中移动和旋转如z 和localRotationY.在plane 上附着一个图片,有一个常见的问题,当旋转plane 时图片会被扭曲.可以通过增加段的数量来避免此问题.增加段数的同时也必须加倍小心.增加的段数越多,需要消耗更多的渲染能力.太多的三角面片会导致Flash player 很难控制此对象.通常来说整个场景的段数总数最好在3000以下.与Flash 的影片剪辑相同,每一个基本体有一个注册点.影片剪辑的注册点默认是(0,0),3D 对象是(0,0,0),定位在场景中心或对象原点.然而在影片剪辑中注册点是可以改变的,但Papervision3D 对象的注册点不能轻易变更.如果现在发布工程将看到一个正在旋转的平面,但是,此平面仅有一面有线框(wireframe)材质.线框是基本体的默认材质当不指定材质时便用线框.显示双面材质的一种方式是设臵plane的meterial属性,将doubleSided属性设为true.plane.material.doubleSided = true;将其加入到init()方法的plane初始化后,会让平面的双面都有材质.球体Sphere前面已经创建过球体.为了保持前后一致,我们将BasicViewExample的代码粘贴到SphereExample的文档类中,注意同时修改类与构造器的定义.代码如下:package {import flash.events.Event;import org.papervision3d.objects.primitives.Sphere;import org.papervision3d.view.BasicView;public class SphereExample extends BasicView{private var sphere:Sphere;public function SphereExample (){init();startRendering();}这里有一些旋转Papervision3D中的对象方式.localRotationX,localRotationY,localRotaionZ属性会对象沿着自己的x,y,z轴旋转.这些值为角度,如plane.localRotationY = 45将使plane绕自身y轴旋转45度.细看DisplayObject3DPapervision3D文档这样描述DisplayObject3D:DisplayObject3D类代表了在场景中的3D对象的实例听起来在3D场景中没有比它更值得关注的了.你可以说DisplayObject3D对象实际上是虚的,有很多子类.不止基本体是DisplayObject3D的子类,Camera类和DAE(载入外部模块到Papervision3D中)类也是,DisplayObject3D有一些关键的属性和方法,可被3D对象使用的.从本章起整本书都在讨论这些属性和方法.随着收到邮件的增多,Papervision3D社区接纳了do3D,这是3d显示对象的缩写.这不止引用了一个DisplayObject3D的实例也代表了一个DisplayObject3D子类的实例.因此,一个Plane类的实例不但可以说是一个Plane类的实例同时是一个do3D.private function init():void{sphere = new Sphere();scene.addChild(sphere);}override protected function onRenderTick(e:Event=null):void{sphere.localRotationY--;super.onRenderTick();}}}我们实例化的球体只有外边有材质.记住不传递任何材质与传递null一样-都将使用线框材质.让我们详细看下Sphere有参构造.改变init()中的这行:sphere = new Sphere();为sphere = new Sphere(null,300,16,12);如果你想知道可以给Sphere构造器(或其他基本体的构造器)传递什么参数,可以参考下文档. 查找Sphere类然后查看构造器细节.将会看到这行:public function Sphere(material:MaterialObject3D = null, radius:Number= 100, segmentsW:int = 8, segmentsH:int = 6)这是Sphere构造器的第一部分.显示了实例化球体可用的参数.下面的表格进行说明:参数数据类型默认值说明1 material MaterialObject3D Null 定义附加到球体表面的材质2 radius Number 100 设臵球体半径(球体中心与顶点的距离)3 segmentsW Number 8 设臵水平段数量4 segmentsH Number 6 设臵竖直段数量花点时间来练习使用这些值.需要注意的是增加段的数量会降低对象移动的平滑度.原因是越多的段数,将会创建更多的顶点和三角面片,Flashplayer渲染起来就越费劲.圆柱Cylinder创建一个圆柱体并将其加入到场景中跟之前的平面与球体类似.如果你准备继续动手的话,我们将继续创建工程和文档类,命名为CylinderExample.导入Cylinder类:import org.papervision3d.objects.primitives.Cylinder;在init()中我们实例化基本体并赋值给局部变量.之后将圆柱体添加到场景中.private function init():void{var cylinder:Cylinder = new Cylinder(null,80,400,8,2,-1,false,true);scene.addChild(cylinder);}发布之后将看到圆柱体Cylinder 构造器有8个参数可以传递参数 数据类型默认值 说明1 material MaterialObject3D null 设臵圆柱体的材质2 radius Number 100 圆柱体的半径3 height Number 100 圆柱体的高4 segmentsW Number 8 圆柱体水平段数5 segmentsH Number6 圆柱体竖直段数 6topRadiusNumber-1设臵圆柱体的上表面.允许创建圆台.默认值是-1使上半径与下半径相同 7 topFace Boolean True 上表面是否创建 8bottomFaceBooleanTrue下表面是否创建同时设定topFace 与bottomFace 为false,将创建一个没有上底与下底,像一个管子:圆锥体Cone你可能已经注意到了,初始化基本体的关键字都是统一的.惯例.我们从创建一个新工程开始,这时我们会将工程命名为ConeExample.导入Cone 类. import org.papervision3d.objects.primitives.Cone;我们在init()中实例化cone 并传递null 的材质和其他的4个参数,将实例加入到场景. private function init():void {var cone:Cone = new Cone(null,150,400,8,4);牢记.当在方法内使用局部变量实例化对象时,不能在方法外进行访问.如果想在onRenderTick()方法内操作对象如旋转,只能将实例指定为类的属性.scene.addChild(cone);}Cone构造器可用的参数参数数据类型默认值说明1 material MaterialObject3D Null 圆锥的材质2 radius Number 100 圆锥的半径3 height Number 100 圆锥的高4 segmentsW Number 8 水平段数量5 segmentsH Number6 竖直段数量圆锥的顶部都是尖的,只能改变圆锥的底半径.立方体Cube前面的章节我们已经创建过一个平面, 一个球体, 一个圆柱体和一个圆锥体.在这些例子中我们都传递了null作为材质参数,导致基本体使用默认的线框材质.虽然初始化立方体跟初始化前面的基本体很类似,但附着材质的方式却有很大的不同.Cube的构造器第一个参数不是材质,是材质列表(materials list).立方体有6个面,通过将材质加入到材质列表,可以为每个面附着上不同的材质.创建材质列表需要导入类MaterialList.同时也导入类Cube,这次我们将使用颜色作为材质,因此还需要导入类ColorMaterial.import org.papervision3d.materials.utils.MaterialsList;import org.papervision3d.materials.ColorMaterial;import org.papervision3d.objects.primitives.Cube;创建一个类的属性:private var cube:Cube;在init()方法中,我们首先创建一个颜色材质,传递16进制颜色值到ColorMaterial的构造器:private function init():void{var red:ColorMaterial = new ColorMaterial(0xFF0000);var blue:ColorMaterial = new ColorMaterial(0x0000FF);var green:ColorMaterial = new ColorMaterial(0x00FF00);现在初始化材质列表.var materialsList:MaterialsList = new MaterialsList();现在我们使用addMaterial()方法将材质加入到材质列表.我们将每个颜色材质附着到立方体相反的2面.materialsList.addMaterial(red,"front");materialsList.addMaterial(red,"back");materialsList.addMaterial(blue,"left");materialsList.addMaterial(blue,"right");materialsList.addMaterial(green,"top");materialsList.addMaterial(green,"bottom");注意下此方法传递的第二个参数如"front"和"back".这个参数是字符串,表示立方体的面.本章之前我们所指的面是另一个词:triangles 三角面片.而当我们提到立方体的面是我们指的的是6个面,而非三角面片.最后,使用材质列表和其余的三个参数来初始化立方体,并将其添加到场景中.cube = new Cube(materialsList,300,300,300);scene.addChild(cube);}现在总结一下Cube 类所使用的参数:参数名 数据类型 默认值 说明 1materials MaterialList 包含显示对象材质属性的列表 2width Number 500 指定宽度 3depth Number 500 指定深度 4height Number 1 指定高度 5segmentsS int 1 宽度段的数量 6segmentsT int 1 高度段的数量 7segmentsH int 1 深度段的数量 8insideFaces int 0 指定立方体内部可见的面数 9 excludeFaces int0 指定不创建的面 参数5,6,7指定段的数量.下图的3个立方体显示了每个参数如何将有1个段的面细分成有2个段的面:当上面的立方体被初始化时,参数5,6,7被赋值为下面的值:● 左,立方体:2,1,1,将与x 轴平行的面划分成2面,(宽度段)● 中,立方体:1,2,1, 将与y 轴平行的面划分成2面,(高度段)● 右,立方体:1,1,2, 将与z 轴平行的面划分成2面,(深度段)下面解释下参数8,9,例子中并没传递.参数insideFaces 指定立方体内部可见的面.假设你的摄影机被放臵到立方体的内部并且你只想显示立方体的后边的面.可以通过传递Cube.BACK 来达成此目的.当传递参数时,可以加减(+,-)相应的面,如传递Cube.ALL-CUBE.LEFT 将显示全部的面除了左边的面.参数excludeFaces 指定不创建的面.这里也可以进行加减(+,-).传递Cube.FRONT+Cube.BACK,创建的立方体将没有前面与后面.如果你想让6个面附着相同的材质,可以给addMaterial()传递字符串'all':materialsList.addMaterial( green,"all");由于cube 是一个类属性,可以在渲染的方法中访问它.让我们让立方体绕3轴进行旋转,借以看到全部外部的面:override protected function onRenderTick(e:Event=null):void{cube.localRotationX++;cube.localRotationY++;cube.localRotationZ++;super.onRenderTick();}纸飞机PaperPlane在本章的介绍中,我们看到,Pavervision3D 项目的纸飞机主要用于测试.为什么纸飞机适合作为一个测试对象,是它特殊的外观-让我们可以清楚的看到它指向的方向及它旋转的方向. 当创建一个3d 物体移动和旋转的应用时可以用它方便的进行测试.假设在场景中有一个线框材质的球体并准备让球体旋转270度.当球体旋转快完成时,很难知道球体正面所面向的方向是否是你所期望的方向.临时将球体替换成纸飞机可以让你更容易的看清物体的运行情况,因为可以清楚的看到纸飞机的位臵和旋转.用之前,须导入类PaperPlane.import org.papervision3d.objects.primitives.PaperPlane;类PaperPlane 的构造器需要2个参数-材质和缩放.下面我们初始化一个放大了3倍的纸飞机,并将其加入到场景中:var paperPlane:PaperPlane = new PaperPlane(null,3);scene.addChild(paperPlane);纸飞机的构造器没有可用的宽度,深度和高度参数,文档中也没有列出相应的默认值. 但如果你需要知道这些值,以便将物体缩放到需要尺寸?我们应该明白:很多时候我们不知道或不能快速访问3d 对象的尺寸,如已被随机指定的值.但可以这样来获取.......注意参数列表中insideFaces 和excludeFaces 的默认值都是0,这也等于是Cube.NONE;下面演示了一个绕自身x 轴旋转90的纸飞机:箭头 Arrow虽然不是不能想象,箭头可能不是你工程中的基本体.但就像纸飞机,箭头也是作为一个方便测试服务的对象,它也可以给你一个明确的方向感.现在你可以在想如何导入此类呢? 如此:import org.papervision3d.objects.primitives.Arrow;箭头的构造器只有一个材质的参数,无参的箭头这样创建:var arrow:Arrow = new Arrow();scene.addChild(arrow);跟以往一样,不传递材质将使用线框材质.与PaperPlane 类似,Arrow 的构造也没可用的尺寸参数.默认值是宽400,高100,深600.如果要改变箭头的尺寸,可使用从DisplayObject3D 对象继承的scale 属性:arrow.scale = 0.5;获取3d 对象的尺寸类Vertices3D.boundingBox()方法计算3d 对象内接长方体并可以获取任意继承自Vertices3D,Papervision3D 内置的,可以在屏幕上显示的3d 对象的宽度,深度和高度.内接长方体刚好将3d 对象容纳其中.下图展示了纸飞机和内接长方体:获取物体内接长方体的尺寸: trace(paperPlane.boundingBox().size); 属性size 返回3个数字代表了对象的顶点在各轴上不同的位置.调用trace 后输出: x:100 y:33.33z::200 表示x,y,z 方向的尺寸.由此可见纸飞机有一个默认的宽度100,默认的高度33.33,和默认的深度200.也可以单独获取每维上的尺寸.下面只输出宽度: trace(paperPlane.boundingBox().size.x); 因此,如果想让纸飞机的宽度为200单元,应该将缩放因子设为2.再者纸飞机继承自DisplayObject3D,可以使用scaleX 和scaleY 来单独设置x 和y 方向的缩放.下图显示了绕自身x轴旋转45度的箭头:嵌套Nesting嵌套是一种将1个或多个对象加入嵌入到一个父对象中的技术.嵌套的好处是你可以创建一个子对象行为与父对象行为有关的层次结构.如可以组织一组对象将他们嵌入到一个父对象中并组织另一组对象嵌入到另一个父对象中.这可以使你按组来控制这些对象.前面的例子中,每当我们创建一个基本体我们直接调用addChild()方法将其添加到场景中.但不只Scene3D对象有这个方法,DisplayObject3D也有.我们看一下类的继承关系:●DisplayObject3D 继承自DisplayObjectContainer3D●Scene3D继承自SceneObject3D,SceneObject3D继承自DisplayObjectContainer3DScene3D和DisplayObject3D都从DisplayObjectContainer3D中继承了addChild()方法.这表示我们也可以在基本体上使用addChild()方法,因为它们继承了DisplayObject3D的属性和方法.现在我们创建一个球嵌套球的工程,命名为NestingExample,之后导入Sphere,将大球体指定为类的属性.private var parentSphere:Sphere;在init()方法中我们先创建一个父球体并将其加入到场景中.private function init():void{parentSphere = new Sphere(null,200,16,12);scene.addChild(parentSphere);接着我们使用局部变量创建一个子球体并将x坐标指定为400.var childSphere:Sphere = new Sphere(null,100,12,8);childSphere.x = 400;现在我们将子球体添加到父球体中而非直接添加到场景.子球体的x为400.我们没指定父球体的坐标,所以它的坐标是场景的原点(0,0,0).现在让我们认识下子球体嵌入到父球体后的坐标系.世界空间vs 本地空间将子球体加入父球体这一刻,子球体的坐标便是与父球体有关的本地坐标.而与全局场景坐标系无关.我们称全局坐标系(与场景有关的坐标系)为世界空间并称本地坐标系为本地空间.因此,每当将DisplayObject3D的实例嵌入时,它便有一个本地坐标.与2D Flash进行比较,在Flash中也可嵌入对象.如可以将一个影片剪辑(MovieClip)嵌入到另一个影片剪辑.假如你将子剪辑嵌入到父剪辑则子剪辑的坐标便于父剪辑的位臵有关.子剪辑将与父剪辑一起被移动和转动.同样,缩放父剪辑同时会缩放子剪辑.现在继续写我们的NestingExample类并在onRenderTick()方法中增加属性localRotationY的值让父球体绕自身y轴旋转:override protected function onRenderTick(e:Event=null):void{parentSphere.localRotationY++;super.onRenderTick();}当发布这个例子时可以看到父球体正绕自身y轴旋转.虽然没让子球体转动,但它也在转.父球体处于世界坐标而非本地坐标.子球体随父球体一起移动因为它的坐标系与父球体有关.如果在渲染方法中输出子球体的x坐标,其值一直是400,因为它并没在本地坐标中移动.当你使用嵌套时必须牢记这个原则.如果你想知道子球体的场景坐标(世界坐标),可以使用属性sceneX.在渲染方法中调用trace(childSphere.sceneX)将持续输出400到-400之间的值.DisplayObject3D也有sceneY和sceneZ属性.下图是正在旋转父球体.注意子球体的x值一直是400而sceneX一直在变化.将3d对象嵌入到其他的3d对象中很明显有重大的好处.可以将多个对象嵌入到一个父对象中然后控制父对象,如从一点移动到另一点.因为每个子对象的坐标都与父对象有关,他们将与父对象一起移动.因此,可用来替代单独通知每个要移动的对象,通知父对象进行移动则所有的子对象都会移动.用DisplayObject3D创建一个基本点常用的嵌套技术是创建一个DisplayObject3D的实例作为其他对象的容器(如基本体).这与前节中类似.但是,这时父对象不是基本体,而是DisplayObject3D的实例.如果你创建一个do3D(译注:DisplayObject3D)并将其加入到场景,将发现在场景无法看到它,因为它不是由顶点和三角面片组成.然而与基本体类似它有addChild()方法表明它可以容纳其他的对象.同时do3D也有全部的移动和转动的属性和方法.do3D将作为子对象的一个基本点(像前节中的父球体那样).要访问类DisplayObject3D需要先导入.import org.papervision3d.objects.DisplayObject3D;下面的代码显示了部分类PivotDO3DExample.注意与前节的类NestingExample很类似.此时我们将DisplayObject3D的实例指定为类属性.private var pivotDO3D:DisplayObject3D;在init()方法中我们创建do3D并将其加入到场景.private function init():void{pivotDO3D = new DisplayObject3D();scene.addChild(pivotDO3D);接着,我们创建子球体并将其x坐标设为400.var childSphere:Sphere = new Sphere(null,100,12,8);childSphere.x = 400;将子球体加入到do3D中:pivotDO3D.addChild(childSphere);}在渲染方法中我们让父对象绕自身y轴旋转.override protected function onRenderTick(e:Event=null):void{pivotDO3D.localRotationY++;super.onRenderTick();}如果你将此类与NestingExample进行比较你会发现我们只是将parentSphere换成了DisplayObject3D的实例:pivotDO3D.将子对象加入到pivotDO3D使子对象的坐标系与它有关.这时发布后会发现球体绕pivotDO3D这个虚拟点旋转,这正如NestingExample 中子球体同父球体一起移动相同.访问顶点现在我们复习一下3D对象的基本要素-顶点.每个3D对象的顶点都存放在一个数组中.可以通过属性geometry进行访问.do3D.geometry.vertices假设你想知道类PlaneExample的平面中所有顶点的x,y坐标.因为顶点存放在数组中,可以使用length属性查看有多少个.var numberOfVertices = plane.geometry.vertices.length;此时可以通过for循环遍历.for(var i:uint = 0; i < numberOfVertices; i++){trace("x: " + plane.geometry.vertices[i].x,"y: " + plane.geometry.vertices[i].y,"z: " + plane.geometry.vertices[i].z)}输出:x: -150 y: -150 z: 0x: -150 y: 150 z: 0x: 150 y: -150 z: 0x: 150 y: 150 z: 0如你所见,只输出了4个点的x,y,z.你可以会认为是6个点,因为每个三角行有3个点而现在。