koorio.com
海量文库 文档专家
当前位置:首页 >> 数学 >>

PV3D-3.基本几何体


基本几何体
如果你熟悉 Maya,3DstudioMax,或 CINEMA4d 等建模软件,会发现软件里往往有一 些内置的基本形体.基本体是一些基本的几何图形如平面,球体,立方体.大多数建模软件通过 单击拖拽等操作就可以创建出基本体,或修改它.当然也可以自己建,但 3d 建模软件里的基本 体为建模者提供了一种捷径. Papervision3D 也包含一些基本形体.Pap

ervision3D 没有图形界面不能通过点击拖拽等 操作来创建几何体.但在程序里却可以随时方便的使用它们. 修改 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 对象的宽度,高度和深度.

如果你熟悉 3d 建模,可能会对 Papervision3D 里的多边形规则感到 惊讶.大多数建模软件多边形被定义成面,至少有 4 个角由 2 个或多 个三角形组合而成,Papervision3D 不能识别这样的多边形,也不含 有 Polygon 类.实际上 Papervision3D 仅支持三角面或三角多边形.

通过设置顶点 x,y,z 的坐标,Papervision3D 便知如何在 2d 屏幕上创建它们以便产生 3d 的 视觉.换句话说,Papervision3D 知道如何在 2d 空间中表示 3d 形体. Papervision3D 类库中,类 Vertices3D 负责创建顶点,TriangleMesh3D 类负责创建由顶点 和三角面组成的 3d 对象.如我们所见,用这些可很容易创建出基本体. 当顶点确定了对象的形状时,三角面则是材质的轮廓,可以是简单颜色或位图甚至视 频.Papervision3D 包含了各种各样的材质类,可用其创建有趣并真实的物体.前面已经涉及 到了材质,但只是简单的使用了线框和颜色等基础材质.(第 4 章通篇讲解如何使用材质).

渲染管道

发布工程,为了让 2d 屏幕出现 3d 视觉,Papervision3D 还需要处理几个过程.将 3d 信息转 换到 2d 屏幕,这个过程的顺序称为:渲染管道(rendering pipeline) 渲染管道(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) 的作用类似. 犹他州茶壶是一种 3d 模型,Martin Newell,1975 年在妻子 Sandra 为 他们的茶服务建立模型的建议下创建的.众所周知对于快速测试非常 有用.原始的茶壶模型现在陈列在加拿大计算机历史博物馆中 Papervision3D 里的基本形体很容易使用.我们将通过例子来说明每个基本体如何创建并如 何加入到场景中. 在第 2 章我们写过一个模板类,所以不必一遍一遍的写基本的代码.我们已经知道了如何以模 板为基础开始新工程,每当你准备动手敲一遍本书的代码时都可以这样做.可以在 Fla 中处理 并调用你的第一个 PlaneExample 例子程序.如果用的是 flex,flashbuilder 通常是一个 ActionScript 工程伴随一个同名的文档类在文档类中调用.现在我们来看一下第一个基本 体:Plane

Plane
平面是基本体中最简单的形体.如果你不旋转它,它看起来就是一个 2d 矩形.只需要将其引入, 创建后加入到场景即可. 前面已经建立了一个 PlaneExample,现在只需要加入几行代码.

package { import flash.events.Event; import org.papervision3d.view.BasicView; import org.papervision3d.objects.primitives.Plane; public class PlaneExample extends BasicView { plane:Plane; private var plane:Plane; public function PlaneExample() { stage.frameRate = 40;

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 2 3 4 5 material width height segmentsW SegmentsH 数据类型 MaterialObject3D Number Number Number Number 默认值 null 0 0 0 0 说明 应用到 plane 的材质 设置 plane 的 width 设置 plane 的 height 设置水平段的数量 设置竖直段的数量

例子中 material 为 null,将应用默认的线框材质 WireframeMaterial.第 5,6 个参数定义了 段的数量.用下图来说明:

左侧的 plane 有一个宽度段和一个高度段.中间的有 2 个宽度段和一个高度段.右侧的 plane 有 2 个宽度和 2 个高度段.正如所见,每增加一个宽度或高度段会多 2 个三角面片.

在 plane 上附着一个图片,有一个常见的问题,当旋转 plane 时图片会被 扭曲.可以通过增加段的数量来避免此问题.增加段数的同时也必须加 倍小心.增加的段数越多,需要消耗更多的渲染能力.太多的三角面片会 导致 Flash player 很难控制此对象.通常来说整个场景的段数总数最好 在 3000 以下.

虽然段数默认值为 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. 与 Flash 的影片剪辑相同,每一个基本体有一个注册点.影片剪辑的注册 点默认是(0,0),3D 对象是(0,0,0),定位在场景中心或对象原点.然而在影 片剪辑中注册点是可以改变的,但 Papervision3D 对象的注册点不能轻易 变更. 在渲染场景的方法内,我们添加另一个属性,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.

这里有一些旋转 Papervision3D 中的对象方式. localRotationX,localRotationY,localRotaionZ 属性会对象沿着自 己的 x,y,z 轴旋转.这些值为角度,如 plane.localRotationY = 45 将使 plane 绕自身 y 轴旋转 45 度. 如果现在发布工程将看到一个正在旋转的平面,但是,此平面仅有一面有线框(wireframe)材 质.线框是基本体的默认材质当不指定材质时便用线框.显示双面材质的一种方式是设置 plane 的 meterial 属性,将 doubleSided 属性设为 true.

plane.material.doubleSided = true;
将其加入到 init()方法的 plane 初始化后,会让平面的双面都有材质. 细看 DisplayObject3D Papervision3D 文档这样描述 DisplayObject3D:

DisplayObject3D 类代表了在场景中的 3D 对象的实例
听起来在 3D 场景中没有比它更值得关注的了. 你可以说 DisplayObject3D 对象实际上是虚的,有很多子类.不止基本体是 DisplayObject3D 的 子 类 ,Camera 类 和 DAE( 载 入 外 部 模 块 到 Papervision3D 中)类也是,DisplayObject3D 有一些关键的属性和方法,可 被 3D 对象使用的.从本章起整本书都在讨论这些属性和方法. 随着收到邮件的增多,Papervision3D 社区接纳了 do3D,这是 3d 显示对象 的 缩 写 . 这 不 止 引 用 了 一 个 DisplayObject3D 的 实 例 也 代 表 了 一 个 DisplayObject3D 子类的实例.因此,一个 Plane 类的实例不但可以说是一 个 Plane 类的实例同时是一个 do3D.

球体 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(); }

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 2 3 4 material radius segmentsW segmentsH 数据类型 MaterialObject3D Number Number Number 默认值 Null 100 8 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);

} 发布之后将看到圆柱体

牢记.当在方法内使用局部变量实例化对象时,不能在方法外进行访问.如 果想在 onRenderTick()方法内操作对象如旋转,只能将实例指定为类的 属性.

Cylinder 构造器有 8 个参数可以传递 参数 1 2 3 4 5 6 material radius height segmentsW segmentsH topRadius 数据类型 MaterialObject3D Number Number Number Number Number 默认值 null 100 100 8 6 -1 说明 设置圆柱体的材质 圆柱体的半径 圆柱体的高 圆柱体水平段数 圆柱体竖直段数 设置圆柱体的上表面.允 许创建圆台.默认值是-1 使上半径与下半径相同 上表面是否创建 下表面是否创建

7 8

topFace bottomFace

Boolean Boolean

True True

同时设定 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);

scene.addChild(cone); } Cone 构造器可用的参数 参数 1 2 3 4 5 material radius height segmentsW segmentsH 数据类型 MaterialObject3D Number Number Number Number 默认值 Null 100 100 8 6 说明 圆锥的材质 圆锥的半径 圆锥的高 水平段数量 竖直段数量

圆锥的顶部都是尖的,只能改变圆锥的底半径.

立方体 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 个面,而非三角面片. 如果你想让 6 个面附着相同的材质,可以给 addMaterial()传递字符 串'all': materialsList.addMaterial( green,"all"); 最后,使用材质列表和其余的三个参数来初始化立方体,并将其添加到场景中. cube = new Cube(materialsList,300,300,300); scene.addChild(cube); } 现在总结一下 Cube 类所使用的参数: 参数名 1 2 3 4 5 6 7 8 9 materials width depth height segmentsS segmentsT segmentsH insideFaces excludeFaces 数据类型 MaterialList Number Number Number int int int int int 500 500 1 1 1 1 0 0 默认值 说明 包含显示对象材质属性的列表 指定宽度 指定深度 指定高度 宽度段的数量 高度段的数量 深度段的数量 指定立方体内部可见的面数 指定不创建的面

参数 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,创建的立方体将没有前面与后面.

注意参数列表中 insideFaces 和 excludeFaces 的默认值都是 0,这也 等于是 Cube.NONE; 由于 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 对象的尺寸,如已被随机指定的值. 但可以这样来获取.......

获取 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 轴旋转 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;

下图显示了绕自身 x 轴旋转 45 度的箭头:

嵌套 Nesting
嵌套是一种将 1 个或多个对象加入嵌入到一个父对象中的技术.嵌套的好处是你可以创建一 嵌套 个子对象行为与父对象行为有关的层次结构.如可以组织一组对象将他们嵌入到一个父对象 中并组织另一组对象嵌入到另一个父对象中.这可以使你按组来控制这些对象. 前面的例子中,每当我们创建一个基本体我们直接调用 addChild()方法将其添加到场景中. 但不只 Scene3D 对象有这个方法,DisplayObject3D 也有.我们看一下类的继承关系: DisplayObject3D 继承自 DisplayObjectContainer3D Scene3D 继承自 SceneObject3D,SceneObject3D 继承自 DisplayObjectContainer3D Scene3D 和 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: 0 x: -150 y: 150 z: 0 x: 150 y: -150 z: 0 x: 150 y: 150 z: 0 如你所见,只输出了 4 个点的 x,y,z.你可以会认为是 6 个点,因为每个三角行有 3 个点而现在

有 2 个三角形.然而,在同一位置上我们不需要 2 个相同的点.他们被三角形共享.设想如果一 个复杂的对象有成百上千的三角行,当对象被渲染时少了 2 个点性能确实会大不同.这将节省 Flash player 的计算和内存占用,从而提升影片的性能. 坐标(x,y,z)都是可读写的属性.刚才我们只读取了坐标,写入同样容易.下面这行设置第一个 顶点的 x 坐标为-300; plane.geometry.vertices[0].x = -300; 这会形成一变形图形.数组中第一个顶点显然与左三角的左底顶点不同.

现在看一下设置顶点的 z 坐标会发生什么: plane.geometry.vertices[0].z = 100;

2d 的屏幕马上显示出了 3d 效果.左底顶点离我们稍远.虽然这是很简单的变化但说明了我们 可以按需求自定义对象. 也可以通过 geometry 属性来访问对象的三角面片: do3D.geometry.faces

例子 - 创建由球体组成的球体
要实现此例子,须先了解基本体顶点的坐标,接着: 创建一个球体 找出所有顶点的坐标 在大球体的每个顶点的位置上放置一个小球体 此例取名为 VerticesExample.首位我们需要引入 DisplayObject3D 来创建基本点. import org.papervision3d.objects.DisplayObject3D; 接着,我们将 DisplayObject3D 实例声明为类属性.用它来做所有小球体的容器. private var pivotDO3D:DisplayObject3D; 在 init()方法中,初始化 DisplayObject3D 对象.同时创建一个大球体. private function init():void { pivotDO3D = new DisplayObject3D(); scene.addChild(pivotDO3D); var bigSphere:Sphere = new Sphere(null,500); 我们不需将大球体加入到场景,也不需附着材质因为我们不准备显示它.虽然我们不将球体 加入,但我们依然可以获取并使用它.在此例中我们将使用它的坐标.一旦我们知道每个顶点 的(x,y,z)属性,我们便可以在这些坐标上放置其他的对象.

还是在 init()方法中,我们加入一个 for 循环变量大球体的顶点数组. var numberOfVerts:uint = bigSphere.geometry.vertices.length; for(var i:uint = 0; i < numberOfVerts; i++) { 在 此 循 环 中 我 们 在 每 次 遍 历 中 都 初 始 化 一 个 小 球 体 , 传 递 null 作 为 材 质 并 且 使 用 Math.random()方法给球体指定一个随机半径.由于小秋天的形状如钻石,我们将其段数降 低. var smallSphere:Sphere = new Sphere(null,Math.random() * 30,2,2); 现在我们使用属性 geometry.vertices,在大球体的顶点坐标中放置小球体. smallSphere.x = bigSphere.geometry.vertices[i].x; smallSphere.y = bigSphere.geometry.vertices[i].y; smallSphere.z = bigSphere.geometry.vertices[i].z; 最后,将小球体加入到 pivotDO3D--DisplayObject3D 的实例无可视化,只作为容器或基本 点. pivotDO3D.addChild(smallSphere); } } 现在将下面的 onRenderTick()方法加入,此例便完成: override protected function onRenderTick(e:Event=null):void { pivotDO3D.localRotationY--; super.onRenderTick(); } 发布后将看到有许多小球体,外形像绕自身 y 轴旋转的大球体的形状.

我们不直接将小球体加入到场景因为很难在同一时间对他们进行控制.将其加入到父 do3D 中可以容易的为所有的子添加动画,使其绕虚拟的大球体进行旋转.

总结
基本体是基本的几何图形如圆锥,立方和球.Papervision3D 库包含了一些基本体,可以直接 使用而不必自己创建他们.我们为每个基本体都写了一个例子用来演示怎么初始化和怎样将 将其加入到场景.也讨论了一些可用的参数如段的数量和准备附着的材质. 每个 3D 对象都是 3d 空间的顶点构成,顶点构造于 2d 屏幕上并最终形成三角面片.每个三角 面片有 3 顶点构成,众多的三角形成一个 3D 对象或三角网.

发布时的处理顺序被称为渲染管道.Papervision3D 的渲染管道是这样: 初始化 创建视角(viewport),场景(scene),摄影机(camera),渲染器(renderer)和 3d 可 视对象及他们的材质的部分. 投影 转换 3d 坐标到 2d 屏幕上.投影只处理顶点,不管三角和材质. 渲染 绘制出在屏幕上可以看到的图,用材质信息组合 2d 投影数据.只处理三角不处 理顶点.此部分最耗处理器资源. 可以将 3d 对象之间加入到场景,也可以将其嵌入到其他的 3d 对象.常用的嵌套技巧是使用 DisplayObject3D 作为其他 3d 可视对象的容器.通过调用 addChild()方法将一个 3d 对象 加入到场景或其他的 3d 对象. 基本体从 DisplayObject3D 继承属性和方法.本章涉及到的属性有: x: 距离原点或其父对象的 x 轴上的距离 Y: 距离原点或其父对象的 y 轴上的距离 Z: 距离原点或其父对象的 z 轴上的距离 localRotationX: 绕自身 x 轴旋转 localRotationY: 绕自身 y 轴旋转 localRotationZ: 绕自身 z 轴旋转 Geometry: 访问对象的几何信息(顶点和三角) sceneX: x 轴上对象距离场景原点的距离 sceneY: y 轴上对象距离场景原点的距离 sceneZ: z 轴上对象距离场景原点的距离 scale: 3d 缩放从对象的原点开始起作用 本章,我们使用了 2 个材质-线框和颜色.但 Papervision3D 有更多的材质.下一章我们将使用 所有的材质让我们的对象看起来更有趣.


更多搜索:PV3D-3.基本几何体
推荐相关:

PV3D-3.基本几何体

PV3D-3.基本几何体_数学_高中教育_教育专区。PV3d基本几何体如果你熟悉 Maya,3DstudioMax,或 CINEMA4d 等建模软件,会发现软件里往往有一 些内置的基本形体.基本体...


molehill介绍翻译

12页 免费 PV3D-3.基本几何体 19页 免费如要投诉违规内容,请到百度文库投诉中心;如要提出功能问题或意见建议,请点击此处进行反馈。 ...


Pv3D-10.粒子

PV3D-3.基本几何体 19页 免费 PV3D-2.构建你的第一个应... 17页 免费 Pv3D...P​V​3​d10 粒子粒子是 2D 图形,它们相对于 3D 坐标系定位,但不使...


pv3d基础学习

学习 几何体pv3d 提供几种基本体:平面 球体 圆柱体 圆锥体 立方体 箭头 ...(material,640,480,3,3) scene.addChild(plane) } override protected ...


PV3D_Book_整理

Pv3d 里面描述一个无限大的三维平面,及其相关运算,是使用 Plane3D 这个类 var ...PV3D-3.基本几何体 19页 免费 Pv3D-8.外部模型 22页 免费 Pv3D-5.摄影机 ...

网站首页 | 网站地图
All rights reserved Powered by 酷我资料网 koorio.com
copyright ©right 2014-2019。
文档资料库内容来自网络,如有侵犯请联系客服。zhit325@126.com