创建 3D 填充
所有点,并从头到尾全部用线连接上了。现在所需的全部就是加入 beginFill 和 endFill,如
FilledE.as 文件中的代码。运行结果如图 16-7 所示。代码相应的变化部分用粗体表示:
graphics.clear();
graphics.lineStyle(0);
graphics.beginFill(0xffcccc);
graphics.moveTo(points[0].screenX, points[0].screenY);
for (i = 1; i < numPoints; i++) {
}
graphics.lineTo(points[0].screenX, points[0].screenY);
graphics.endFill();
图 16-7 第一个 3D 填充
的图形。因此,三角形就是一个最简单的多边形。我们发现在许多 3D 建模或渲染的程序
中—— 甚至那些使用面片(patches),网格(meshes),非均匀 B 样曲线(NURBS)以及
复合多边形 —— 在渲染之前,所有的 3D 图形最终都简化为一个三角集合。
运用三角形
运用三角形我们能够确定多边形的所有顶点都在一个平面上,因为一个三角形定义一个平
面。如果大家还不确定为什么它很重要,那么我们就拿字母 E 的例子来说,随机地改变一
些点的 z 值。这时可能会得到一些有趣的结果,这些结果也很快会变成不可预想或不可预
知的。
图 16-8 更加复杂的 3D 图形
可能遇到这样的情况, 我们创建的每个多边形的顶点都有不同的数值并需要特别的处理。此
外,使用三角形可以创建如图 16-9 所示 A 这样的模型。
图 16-9 如图 16-8,用三角形重新渲染
顶点的列表和一个三角形的列表。一层循环顶点列表,设置所有顶点的位置,并应用透视。
另一层循环遍历三角形列表并渲染每个三角形。
是这里为了保证简单与灵活,让我们从三角形开始吧。先来试验字母 A 这个例子。
编号。
图 16-10 组成该形状的顶点与多面形
points[0] = new Point3D( -50, -250, 100);
points[1] = new Point3D( 50, -250, 100);
points[2] = new Point3D( 200, 250, 100);
points[3] = new Point3D( 100, 250, 100);
points[4] = new Point3D( 50, 100, 100);
points[5] = new Point3D( -50, 100, 100);
points[6] = new Point3D(-100, 250, 100);
points[7] = new Point3D(-200, 250, 100);
points[8] = new Point3D( 0, -150, 100);
points[9] = new Point3D( 50, 0, 100);
points[10] = new Point3D(-50, 0, 100);
为了能够明确知道每个三角形的所有顶点,我们来创建一个三角形的类(Triangle class)。甚
至还可以为每个三角形写一个 draw 方法,让它自己就可以进行绘制。我把代码列出来,稍
后会看到如何使用它。
package {
}
现在我们需要另一个数组来保存三角形的列表。因此,请在类的顶部定义一个数组:
然后,在定义了所有的顶点后,再在 init 函数中定义所有三角形。注意每个三角形都用指
定的颜色创建。
triangles = new Array();
triangles[0] = new Triangle(points[0], points[1], points[8], 0xffcccc);
triangles[1] = new Triangle(points[1], points[9], points[8], 0xffcccc);
triangles[2] = new Triangle(points[1], points[2], points[9], 0xffcccc);
triangles[3] = new Triangle(points[2], points[4], points[9], 0xffcccc);
triangles[4] = new Triangle(points[2], points[3], points[4], 0xffcccc);
triangles[5] = new Triangle(points[4], points[5], points[9], 0xffcccc);
triangles[6] = new Triangle(points[9], points[5], points[10],0xffcccc);
triangles[7] = new Triangle(points[5], points[6], points[7], 0xffcccc);
triangles[8] = new Triangle(points[5], points[7], points[10],0xffcccc);
triangles[9] = new Triangle(points[0], points[10], points[7], 0xffcccc);
triangles[10] = new Triangle(points[0], points[8], points[10],0xffcccc);
前这个程序来说并不重要,但是在下一章就非常重要了,因此应该养成这样的好习惯。
graphics.clear();
for (i = 0; i < triangles.length; i++) {
}
了!三角形根据定义的颜色开始填充,移动到第一个点的位置上,绘制一个图形出来,结束
填充。您也许会说,太精致了。
Triangle 类非常容易理解,主类部分也是再简单不过了。与本书前一版所使用的那个更加复
杂并且需要大量解释的线性解决方案相比,这是最好的答案。
图 16-11 A 形
package {
}
}
3D 立体建模
“Hello,World”。在 3D 立体编程中,就相当于一个旋转立方体的程序。我们也不要打破这
个传统。
建立旋转立方体模型
图 16-12 3D 立方体的顶点
代码中点的定义如下:
// 前面四个角
points[0] = new Point3D(-100, -100, -100);
points[1] = new Point3D( 100, -100, -100);
points[2] = new Point3D( 100, 100, -100);
points[3] = new Point3D(-100, 100, -100);
// 后面四个角
points[4] = new Point3D(-100, -100, 100);
points[5] = new Point3D( 100, -100, 100);
points[6] = new Point3D( 100, 100, 100);
points[7] = new Point3D(-100, 100, 100);
—— 六个面,每面两个。同样,我会为每个三角形以逆时针的方向排列这些点。这里有个
小技巧,试将立方体按照您的意思旋转,让这些三角形面向我们,然后将这些点以观察点的
顺时针方向排列。
图 16-13 立方体的正面
图 16-15 立方体的背面
// front
triangles[0] = new Triangle(points[0], points[1], points[2], 0x6666cc);
triangles[1] = new Triangle(points[0], points[2], points[3], 0x6666cc);
// top
triangles[2] = new Triangle(points[0], points[5], points[1], 0x66cc66);
triangles[3] = new Triangle(points[0], points[4], points[5], 0x66cc66);
//back
triangles[4] = new Triangle(points[4], points[6], points[5], 0xcc6666);
triangles[5] = new Triangle(points[4], points[7], points[6], 0xcc6666);
// bottom
triangles[6] = new Triangle(points[3], points[2], points[6], 0xcc66cc);
triangles[7] = new Triangle(points[3], points[6], points[7], 0xcc66cc);
// right
triangles[8] = new Triangle(points[1], points[5], points[6], 0x66cccc);
triangles[9] = new Triangle(points[1], points[6], points[2], 0x66cccc);
// left
triangles[10] =new Triangle(points[4], points[0], points[3], 0xcccc66);
triangles[11] =new Triangle(points[4], points[3], points[7], 0xcccc66);
目前来看,是否使用顺时针方向无关紧要,但是在下一章,我们要在背面剔除中用到它。这
个术语是指决定哪个面面向我们的一种方法。大家马上会看到为什么如此重要的原因。
Cube.as 文件与 Triangles.as 非常像,只不过是在 init 函数中使用了这些新的点和三角形的
进行定义。
看不可见。为什么会这样呢?立方体的背面总是被绘制出来。同样,那两个三角形也根据它
们在 triangles 数组中的位置进行绘制。因此在列表底部的面总是在列表顶部面之前被绘制
出来,您会感到奇怪,不可预知的效果就是这样形成的。我们需要调用 cull(剔除),或铲掉、
清除这些背面,因为它们不需要渲染。
基本的灯光。
明度为 0.5:
public function draw(g:Graphics):void {
}
之前这只是个临时性的修正。完成后的 3D 立方体如图 16-16 所示。
图 16-16 3D 立方体运行结果
建立其它形状的模型
将它们绘制在方格纸上,标出点和三角形,再将放入数组即可。这张图可以帮助我们用几种
视角绘出物体,
形作为起点。
金字塔形
首先是点:
points[0] = new Point3D( 0, -200, 0);
points[1] = new Point3D( 200, 200, -200);
points[2] = new Point3D(-200, 200, -200);
points[3] = new Point3D(-200, 200, 200);
points[4] = new Point3D( 200, 200, 200);
triangles[0] = new Triangle(points[0], points[1], points[2], 0x6666cc);
triangles[1] = new Triangle(points[0], points[2], points[3], 0x66cc66);
triangles[2] = new Triangle(points[0], points[3], points[4], 0xcc6666);
triangles[3] = new Triangle(points[0], points[4], points[1], 0x66cccc);
triangles[4] = new Triangle(points[1], points[3], points[2], 0xcc66cc);
triangles[5] = new Triangle(points[1], points[4], points[3], 0xcc66cc);
运行结果如图 16-17 所示。
图 16-17 一个 3D 金字塔
挤出的字母 A
前面 11 个点,将一个字母的 z 设置为 -50,另一个设置为 +50,然后为第二个设置三角
形(确认它们也是顺时针排列的) ,最后用三角形连接两边。很乏味?当然!但是完成后的
效果非常好:
points[0] = new Point3D( -50, -250, -50);
points[1] = new Point3D( 50, -250, -50);
points[2] = new Point3D( 200, 250, -50);
points[3] = new Point3D( 100, 250, -50);
points[4] = new Point3D( 50, 100, -50);
points[5] = new Point3D( -50, 100, -50);
points[6] = new Point3D(-100, 250, -50);
points[7] = new Point3D(-200, 250, -50);
points[8] = new Point3D( 0, -150, -50);
points[9] = new Point3D( 50, 0, -50);
points[10] = new Point3D( -50, 0, -50);
points[11] = new Point3D( -50, -250, 50);
points[12] = new Point3D( 50, -250, 50);
points[13] = new Point3D( 200, 250, 50);
points[14] = new Point3D( 100, 250, 50);
points[15] = new Point3D( 50, 100, 50);
points[16] = new Point3D( -50, 100, 50);
points[17] = new Point3D(-100, 250, 50);
points[18] = new Point3D(-200, 250, 50);
points[19] = new Point3D( 0, -150, 50);
points[20] = new Point3D( 50, 0, 50);
points[21] = new Point3D( -50, 0, 50);
triangles[0] =new Triangle(points[0], points[1], points[8], 0x6666cc);
triangles[1] =new Triangle(points[1], points[9], points[8], 0x6666cc);
triangles[2] =new Triangle(points[1], points[2], points[9], 0x6666cc);
triangles[3] =new Triangle(points[2], points[4], points[9], 0x6666cc);
triangles[4] =new Triangle(points[2], points[3], points[4], 0x6666cc);
triangles[5] =new Triangle(points[4], points[5], points[9], 0x6666cc);
triangles[6] =new Triangle(points[9], points[5], points[10], 0x6666cc);
triangles[7] =new Triangle(points[5], points[6], points[7], 0x6666cc);
triangles[8] =new Triangle(points[5], points[7], points[10], 0x6666cc);
triangles[9] =new Triangle(points[0], points[10], points[7], 0x6666cc);
triangles[10] = new Triangle(points[0], points[8], points[10], 0x6666cc);
triangles[11] = new Triangle(points[11], points[19], points[12], 0xcc6666);
triangles[12] = new Triangle(points[12], points[19], points[20], 0xcc6666);
triangles[13] = new Triangle(points[12], points[20], points[13], 0xcc6666);
triangles[14] = new Triangle(points[13], points[20], points[15], 0xcc6666);
triangles[15] = new Triangle(points[13], points[15], points[14], 0xcc6666);
triangles[16] = new Triangle(points[15], points[20], points[16], 0xcc6666);
triangles[17] = new Triangle(points[20], points[21], points[16], 0xcc6666);
triangles[18] = new Triangle(points[16], points[18], points[17], 0xcc6666);
triangles[19] = new Triangle(points[16], points[21], points[18], 0xcc6666);
triangles[20] = new Triangle(points[11], points[18], points[21], 0xcc6666);
triangles[21] = new Triangle(points[11], points[21], points[19], 0xcc6666);
triangles[22] = new Triangle(points[0], points[11], points[1], 0xcccc66);
triangles[23] = new Triangle(points[11], points[12], points[1], 0xcccc66);
triangles[24] = new Triangle(points[1], points[12], points[2], 0xcccc66);
triangles[25] = new Triangle(points[12], points[13], points[2], 0xcccc66);
triangles[26] = new Triangle(points[3], points[2], points[14], 0xcccc66);
triangles[27] = new Triangle(points[2], points[13], points[14], 0xcccc66);
triangles[28] = new Triangle(points[4], points[3], points[15], 0xcccc66);
triangles[29] = new Triangle(points[3], points[14], points[15], 0xcccc66);
triangles[30] = new Triangle(points[5], points[4], points[16], 0xcccc66);
triangles[31] = new Triangle(points[4], points[15], points[16], 0xcccc66);
triangles[32] = new Triangle(points[6], points[5], points[17], 0xcccc66);
triangles[33] = new Triangle(points[5], points[16], points[17], 0xcccc66);
triangles[34] = new Triangle(points[7], points[6], points[18], 0xcccc66);
triangles[35] = new Triangle(points[6], points[17], points[18], 0xcccc66);
triangles[36] = new Triangle(points[0], points[7], points[11], 0xcccc66);
triangles[37] = new Triangle(points[7], points[18], points[11], 0xcccc66);
triangles[38] = new Triangle(points[8], points[9], points[19], 0xcccc66);
triangles[39] = new Triangle(points[9], points[20], points[19], 0xcccc66);
triangles[40] = new Triangle(points[9], points[10], points[20], 0xcccc66);
triangles[41] = new Triangle(points[10], points[21], points[20], 0xcccc66);
triangles[42] = new Triangle(points[10], points[8], points[21], 0xcccc66);
triangles[43] = new Triangle(points[8], points[19], points[21], 0xcccc66);
运行结果如图 16-8 所示。
图 16-8 一个被挤出的字母 A
来的四倍!代码仍然运行得非常稳定,但是我们已进入了 Flash 的宏大的 3D 世界。相同
的程序在 AS 2 中运行得也非常好。使用 AS 3 效率会变得更高,目前我不认为已经到达
了它速度的极限。随着 Flay Player 性能的改进,未来会怎样,谁知道呢?
移动三维立体模型
法改变中心位置。我们已经在 z 轴上做过图形的移动。这次只需要在其它轴上做同样的事
情即可。但是,请快速看一下,当改变这些值的时候,执行的代码是什么样的。它们都在
Point3D 类的 screenX 和 screenY 方法中:
public function get screenX():Number {
}
public function get screenY():Number {
}
段距离,并不真正地改变 z 本身的位置。
将一个方向上的点向外推,同样,不会永久改变它们。由于我们从没改变过这些值,这个点
—— 因此会使形状变大 —— 将继续绕着自身的中心旋转,而不是绕着整个世界的中心旋
转。
我们来看一下代码。回到 Cube.as 类,在顶部加入两个类属性:
private var offsetX:Number = 0;
private var offsetY:Number = 0;
并在 init 方法中,加入这样一行:
然后创建处理方法:
private function onKeyDown(event:KeyboardEvent):void {
}
不要忘记导入 KeyboardEvent 和 Keyboard 类。
变,模型就像绕着 3D 空间的中心在旋转。这也许是或不是您想要的。如果我们只想移动
整个模型,并且还想让它绕着自身的中心点旋转,这就是 setCenter 方法出场的时候了。将
onKeyDown 中的代码做如下改变:
private function onKeyDown(event:KeyboardEvent):void {
}
中心旋转。
本章总结:
本章虽然没有新出现的公式,绘制的技巧还是需要多熟悉的。虽然代码很多,但是都相对前面更容易理解
主要重点放在了图形显示上面,如果对3D构图感兴趣可以下去多构思下更复杂的图形比如圆柱,简单的房子外形等等~~
(如果要转载请注明出处http://blog.sina.com.cn/jooi,谢谢)