VRML2.0教程7:不规则几何节点
来源:第三维度
作者:施寅,周葆芳,赵志勇
选自《VRML2.0使用速成》第5章 第3节
Shape(外形)节点像上一章描述的那样, 是构成一个场景的基石。回忆一下, 每个Shape 节点由两部分组成: 外形的几何属性(由geometry 域定义)和外观属性( 由appear-ance 域定义) 。本节在上一章介绍紫色圆柱场景的基础上来进一步讨论几何节点的使用。
现在, 我们暂时不考虑外观属性, 而把目光集中到几何属性上, 以使你所建的造型更真实生动。
一些物体的几何属性是以一系列顶点坐标加上描述这些顶点如何连接成这个物体外型的多面体的信息的形式给出来的, 这类几何造型称为基于顶点的几何造型。其他的物体是比较规则的一类, 它们的几何属性用VRML 预定义好的几种基本造型来给出。VRML 浏览器不必知道构成这些物体的每个多边形坐标就能把它画出来。
VRML 预定义好的四个简单几何节点使用起来非常灵活, 通过变换手段可以满足许多造型需要, 但有时一些复杂的物体用它们却造不出来或过于困难, 比如表面是自由曲面的物体, 这时就需要用到基于顶点的几何节点。
(1) 几何坐标
每个基于顶点的几何节点都包含一系列的顶点。Coordinate ( 坐标)节点用来定义一个三维空间中的坐标集合, 你可以把用它来作基于顶点的几何节点中的一部分。Coordinate节点含有一个域——— point 域, 它包含多个三元浮点数, 每个三元组成的一组定义三维空间中的一个点。下面是使用Coordinate 节点的简单例子, 它会给你一些直观的认识。
[例1] 使用Coordinate 节点。
Coordinate { point [ - 1 - 1 0, # point 0 1 - 1 0, # point 1
1 1 0, # point 2
- 1 1 0 ] # point 3
}
上述例子中定义了一个由四个点组成的集合, 并且这四个点都位于x y 平面上(因为每个点的z 坐标值都是0) ; 如果你用基于顶点的几何节点把它们连起来, 结果是一个正方形。你要注意: Coordinate 节点中的数据不能被本身使用, 而只能放在基于顶点的几何节点中使用, 它是一种辅助性节点而不是功能性节点。
像例子中用注释语句标出的那样, 你可以想像Coordinate 节点中的每个点都有一个引用它的数或称为索引; 开头一个点的索引是0 , 第二个是1 , 以此类推。图1 所示就是上例中四个点连起来形成的正方形, 图中每个顶点的索引都用数字标了出来。
图1 标有序号的多边形
你可能注意到顶点是按逆时针顺序排列的, 但这并不是非如此不可, 只不过在定义多边形时顶点以逆时针顺序排列比较方便一些。
(2) 索引面集节点
三维图形里的模型其表面通常并不光滑, 一般是由许许多多的小多边形平面组成的。例如, 大多数的曲面都可以用大量的小三角面或四边形来逼近。图2所示的是一个曲面和它的放大样子。
图2 显示出多个面的模型
每一个这样的多边形都能用它的顶点来描述, 就像在Coordinate 节点中列出的那样,每个顶点就是三维空间中的一个点。为了画出多边形, 你需要在IndexedFaceSet ( 索引面集)中指定哪个点应该被连接, 以及连接的顺序。一个索引面集包括一系列的顶点( 在coord 域中以Coordinate 节点的方式给出) 和一系列的多边形( 用coordIn dex 域给出)。
每个多边形由组成它的顶点在Coordinate 节点中的索引指定。当画一个索引面集时, 浏览器按指定顺序连接各个顶点来画每一个多边形, 并填充拟合整个外形。对每个多边形,列出的顶点是以任一顶点开头并按逆时针顺序排列的, 这里逆时针顺序是以你从多边形前面看的为准。实际上, 你用顺时针顺序也是可以的, 只要每个多边形都按此顺序处理,并且你把IndexedFaceSet 节点的ccw 域置成FALSE, 但是, 不推荐大家使用顺时针顺序。
为了指示你已经到了一个多边形的最后一个顶点, 应该开始下一个多边形的顶点,VRML 规定在这两个顶点索引间加一个“ - 1”来作为分隔符(因为正常的索引都大于、等于0)。
应该注意, 每个多边形都必须是平的, 也就是说, 它的所有顶应该在同一个平面内。如果你试图画一个不在一个平面的多边形, 其结果是不可预测的(或许会很糟糕)。避免这个问题最简单的方法是只使用三角形, 而不去用其他较为复杂的多边形。任何一个三角形都能保证是在一个平面上, 因为大家很早就知道三点决定一个平面这个公理。阿兹特克神庙模型的大部分都是用索引面集构造的。在神庙模型中最简单的索引面集就是房顶的中间一层, 它处于前面已做好的天花板的上面。
注意: 通常, 用三角面而不用四边形是最佳选择, 但在你能保证每个四边形都是平面的情况下, 用四边形能使节点更加简单。
下列例子以一个Shape 节点开始(在文件中, 它是顶层组节点的一个子节点) , 随后用一个索引面集列出要用到的顶点坐标并指定顶点顺序。
[例2] 使用IndexedFaceSet 节点。
DEF UPPER- WHITE- BAND Shape { geometry IndexedFaceSet {
coord Coordinate {
point [
17 .5 11 .25 - 1 .25, 17 .5 15 - 1 .25,
- 17 .5 15 - 1 .25, - 17 .5 11 .25 - 1 .25,
17 .5 15 - 18 .75, 17 .5 11 .25 - 18 .75,
- 17 .5 11 .25 - 18 .75, - 17 .5 15 - 18 .75 ]}
coordIndex [ 0,1,2,3, - 1, 4,1,0,5, - 1,
6,7,4,5, - 1,
2,7,6,3, - 1 ]
}
}
上例中Coordinate 节点中point 域的每一行描述了两个顶点, coordIndex 域的每一行描述了一个多边形。当然, 这只是为了方便阅读考虑, 如果你愿意, 可以把这些顶点或多边形全部放在一行上, 只要顶点间用逗号隔开, 每个多边形的顶点索引后加一个“ - 1”作结束符。第一个面是按顺序连接索引值为0 , 1 , 2 , 3 的四个顶点(就是Coordinate 节点point 域的前四个点) , 再从顶点3 连回到顶点0 , 最后给这个四边形着上颜色, 与此类似画出另外三个四边形, 它们立在神庙天花板平面的边上, 构成庙顶的中间层。
图3 是你构作的神庙的样子。你仔细看过后可能会以为自己搞错了, 明明在VRML 文件中四个四边形都有, 而图中怎么只看到最近的一个呢, 如果你通过浏览器绕着神庙走一圈就会发现四个四边形其实都有, 只是当四边形的正面对着你时, 你才能看到它, 这是因为索引面集节点solid 域的缺省值是TRUE, 而solid 域的功能是指示你所定义的几何模型是否是一个实体(即在它的外表面上没有孔)。一个物体如果是实体的话,你是不能看到物体的内部的, 所以在画时就不用考虑内表面, 这样就提高了浏览器的渲染速度。solid 域取TRUE 作缺省值是因为一般来说, 场景中的物体大多是实体。在这个特殊情况下, 平面被设成了实体, 所以平面的反面就是实体的内部, 是看不到的。
图3 柱子与天花板
当然, 如果你想建一个内部也能可见的物体, 需要把solid 域设为FALSE, 这样, 背离用户的多边形的那些面, 浏览器也将它们画出来。神庙的剩余部分也是用索引面集构造的(除了上层庙顶, 它是用长方体经过变形处理做的)。然而, 剩余部分用到的索引面集比前面这个仅包含四个面的索引面集要大得多,它用到大量的三角形。幸运的是, 你不用手工去把这些三角形顶点坐标一个个键入计算机中, 你可以从地址:
http://vrml.sgi.com/handbook/examples/temple.gray.wrl
下载到整个神庙的VRML 文件。打开它仔细看一看, 如果你已理解了它的结构, 就继续看下去。
(3) 索引线集节点
除了把带颜色填充的多边形换成线段外, IndexedLineSet (索引线集)节点和Indexed-FaceSet 节点基本上完全一样。IndexedLineSet 节点对线框模型或实体轮廓线的显示是很有用的, 它的渲染速度很快。整个泰诺切蒂特里城场景中唯一用到这类节点的地方是在魁兹科特尔神庙: 当你接近神庙的门时, 一束光线会出现, 这束光线就是用一个索引线集节点来实现的。例5.11 中将介绍这束线的简单做法。
[例3] 使用IndexedLineSet 节点。
# VRML V2 .0 utf8 Transform {
rotation 1 0 0 - 1 .37 # titled down at an angle
scale 8 80 8
children [
Shape {
appearance Appearance {
material Material {
diffuseColor 1 0 .8 0 # bright yellow,
emissiveColor 1 0 .8 0 # to look like sunlight
shininess 1
}
}
geometry IndexedLineSet {
coord Coordinate {
point [
0 - 1 - 1, 0 1 0,
0 .4 - 1 - 0 .9, 0 .7 - 1 - 0 .7,
0 .9 - 1 - 0 .4, 1 - 1 0,
0 .4 - 1 0 .4, 0 .7 - 1 0 .7,
0 .9 - 1 0 .9, 0 - 1 1,
- 0 .4 - 1 0 .9, - 0 .7 - 1 0 .7,
- 0 .9 - 1 0 .4, - 1 - 1 0,
- 0 .9 - 1 - 0 .4, - 0 .7 - 1 - 0 .7,
- 0 .4 - 1 0 .9
]
}
coordIndex
[
]
0, 1, - 1, 2, 1, - 1, 3, 1, - 1, 4, 1, - 1,
5, 1, - 1, 6, 1, - 1, 7, 1, - 1, 8, 1, - 1,
9, 1, - 1, 10, 1, - 1, 11, 1, - 1, 12, 1, - 1,
13, 1, - 1, 14, 1, - 1, 15, 1, - 1, 16, 1, - 1,
}
}
]
}
(4) PointSet ( 点集)节点
PointSet 节点显示了一个像素点大小的点, 它对应于Coordinate 节点中列出的每个顶点。这一节点对制作小的发光物比较有用, 比如机场的控制灯、天上的星星等; 泰诺切蒂特兰场景中它被用来制作火盆里的火焰, 当用户点击一个火盆时, 它就窜了上来。