当前位置:文档之家› 三角网格

三角网格

最简单的情形,多边形网格不过是一个多边形列表;三角网格就是全部由三角形组成的多边形网格。

多边形和三角网格在图形学和建模中广泛使用,用来模拟复杂物体的表面,如建筑、车辆、人体,当然还有茶壶等。

图14.1给出一些例子:当然,任意多边形网格都能转换成三角网格,三角网格以其简单性而吸引人,相对于一般多边形网格,许多操作对三角网格更容易。

表示网格三角网格为一个三角形列表,所以最直接的表示方法是用三角形数组:Listing 14.1: A trivial representation of a triangle meshstruct Triangle {Vector3 p[3];};struct TriangleMesh {int triCount;Triangle *triList;};对于某些应用程序,这种表示方法已经足够。

然而,术语"网格"隐含的相邻三角形的连通性却未在这种简单表示中有任何体现。

实际应用中出现的三角网格,每个三角形都和其他三角形共享边。

于是,三角网格需要存储三类信息:(1)顶点。

每个三角形都有三个顶点,各顶点都有可能和其他三角形共享。

(2)边。

连接两个顶点的边,每个三角形有三条边。

(3)面。

每个三角形对应一个面,我们可以用顶点或边列表表示面。

索引三角网格在索引三角网格中,我们维护了两个列表:顶点表与三角形表。

每个顶点包含一个3D位置,也可能有如纹理映射坐标、表面法向量、光照值等附加数据。

每个三角形由顶点列表的三个索引组成。

通常,顶点列出的顺序是非常重要的,因为我们必须考虑面的"正面"和"反面"。

从前面看时,我们将用顺时针方向列出顶点。

另外一些信息也存在这一级中,如预先计算的表面法向量,表面属性(纹理映射)等。

程序清单14.2给出了一段高度简化的代码:Listing 14.2: Indexed triangle mesh// struct Vertex is the information we store at the vertex level struct Vertex{// 3D position of the vertexVector3 p;// Other information could include texture mapping coordinates, // a surface normal, lighting values, etc.}// struct Triangle is the information we store at the triangle level struct Triangle{// Indices into the vertex listint vertex[3];// Other information could include a normal, material information , etc.}// struct TriangleMesh stores an indexed triangle meshstruct TriangleMesh{// The verticesint vertexCount;Vertex *vertexList;// The trianglesint triangleCount;Triangle *triangleList;};实践中,三角网格类会有一系列方法,用于存取和维护顶点、三角形列表。

当然,存储多边形网格,还需要定义一个多边形类,用来表达有任意多顶点的面。

为简化和提高效率,我们可以对每个多边形的最大定点数做出限制。

注意到,索引三角形列表中的邻接信息是隐含的。

例如:边信息没有直接存储,但我们还是可以通过搜索三角形表找出公共边。

和前面"三角形数组"方式相比,这种方式确实能节省不少空间。

原因是信息存于顶点级别,它的整数索引比之三角形数组里存储的顶点重复率要小得多。

高级技术简单索引三角网格对于基本应用已经足够了,但为了更加高效地实现某些操作还可以进行一些改进。

主要的问题是邻接信息没有显式表达,所以必须从三角形列表中搜索。

另一种表达方法可以在常数时间内取得这种信息。

方法是维护一个边列表,每个边由两个端点定义,同时维护一个共享该边的三角形列表。

这样,三角形可视为三条边而非三个点的列表,也就是说它是边列表而不是点列表的索引。

该思想的一个扩展称作"winged edge"模型,对每一顶点,存储使用该点的边的索引。

针对渲染的特殊表达大多数图形卡并不直接支持索引三角网,渲染三角形时,一般是将三个顶点同时提交。

这样,共享顶点会多次提交,三角形用到一次就提交一次。

因为内存和图形硬件间的数据传输是瓶颈,所以许多API和硬件支持特殊的三角网格式以减少传输量。

基本思想是排序点和面,使得现存中已有的三角形不需要再次传输。

从最高灵活性到最低灵活性,我们讨论三种方案:顶点缓存,三角带,三角扇。

顶点缓存与其说顶点缓存是一种特殊的存储格式,不如说是API和硬件之间的一种存储策略,用以发挥连续三角形顶点一致性的特点。

通常,高级代码不需要了解顶点缓存是如何实现和执行的。

和其他缓存机制类似,顶点缓存基于最近使用的数据将来仍被使用的原则。

图形处理器缓存一小部分(如,16个)最近使用的顶点,当API要发送顶点时,首先探测缓存内是否已存在。

当然,这要求API了解图形卡缓存的大小和替换机制。

若缓存内没有该顶点,则发生脱靶,API发送顶点并更新缓存;若缓存内有该顶点,就命中,API通知图形卡"使用缓存内位置x的顶点"。

顶点缓存其实是一种底层的优化手段,任何三角网都可用高级代码实现正确渲染而不用考虑缓存。

但进行顶点顺序的调整,使共享顶点的三角形集中发送有助于提高效率。

这种调整只需要进行一次,并且可以离线进行,它只会对性能有帮助,不会使没有缓存的系统性能降低。

善用缓存,可能使发送到显卡的顶点数降低到平均每三角形少于一个。

三角带三角带是一个三角形列表,其中每个三角形都与前一个三角形共享一边,图14.2显示了一个三角带的例子。

注意顶点列出的顺序使得每三个连续的点都能构成一个三角形。

例如:(1)顶点1、2、3构成第一个三角形。

(2)顶点2、3、4构成第二个三角形。

(3)顶点3、4、5构成第三个三角形。

在图14.2中,顶点以构成三角形带的顺序编号。

"索引"信息不再需要,因为顶点顺序已经隐式定义了三角形。

通常,列表前部有顶点数目,或末尾处有一特殊码表示"列表结束"。

注意到,顶点顺序在顺指针和逆时针间不断变换(见图14.3)。

某些平台上,需要指出第一个三角形的顶点顺序,而有些平台上顺序是固定的。

最佳情况下,三角带可用n+2个顶点存储n个面。

n很大时,每个三角形平均发送一个顶点,遗憾的是,这只是最佳情况。

实践中,很多网格是一个三角形带无法表达的,不仅如此,3个以上三角形共享的顶点还是要多次发送给图形卡。

从另一方面说,每个三角形至少要发送一个顶点。

但在顶点缓存机制中,有可能将每个三角形发送的顶点数降到一个以下。

当然,顶点缓存需要额外的簿记信息(索引和缓存管理数据),可是尽管这些额外信息对单个顶点来讲相对较大,操作速度也会相对下降,但发送顶点数最少的系统在特定平台上速度最快。

假设用一种生成三角带的直接方法,用三角带表示三角网需要的顶点数为 t+2s,t为三角形数目,s为三角带数目。

每个三角带的第一个三角形对应三个顶点,以后每个三角形对应一顶点。

因为我们希望最小化发往图形卡的顶点数,所以三角带的数目应尽可能少,即三角带越长越好。

STRIPE方法给出了一种三角带数目接近理论下限的生成手段。

另一个希望减少三角形带数目的原因在于建立各三角形需要额外时间。

从另一方面说,分别渲染两个长为n的三角带所需时间长于渲染一个长为2n的三角带,即使这个三角带中的三角形数多于两个分开带中三角形数量的和。

于是,我们经常通过使用退化三角形连接多个三角带,从而将整个网格置于一个连续的三角带中,退化的意思是面积为0。

图14.4显示了如何重复顶点以将两个三角形合并为一个。

图14.4的含义不太明显,但这里有四个退化三角形用于连接两个三角带从而维持正确的顺指针、逆时针顺序。

顶点7、8间的边实际包含两个退化三角形,图14.5指出了图14.4中包含的三角形。

退化三角形面积为0不需要渲染,所以不会影响效率。

实际上要发送到图形卡的顶点仍然只是第一列的顶点:1,2,3,4,5,6,7,8,9,10,11,12,13这符合我们每三个连续顶点表示一个三角形的约定。

一些硬件(如PS2上的GS)可以跳过三角带中的三角形,方法是通过一个顶点上的标志位指出"不必绘制"此三角形。

这给我们一种方法可以有效的从任意点开始新三角形带而不必重复顶点或使用退化三角形。

例如,图14.4中的两个三角带可以如图14.6那样连接,其中灰色表示顶点被标记"不必绘制"。

三角扇三角扇和三角带类似,但不如三角带灵活,所以很少使用。

图14.7所示即为三角扇。

三角网可在三角形或顶点级保存额外信息。

纹理映射坐标纹理映射是将位图(称作"纹理图"或简称"纹理")贴到多边形表面的过程。

这里只给出一个高度简化的解释:我们希望将2D纹理贴到多边形表面上,同时考虑多边形在摄像机空间的方向。

对多边形中每个需要渲染的像素都要计算2D纹理映射坐标,这些坐标用以索引纹理图,从而为相应像素着色。

通常,在顶点保存纹理映射坐标,三角形面中其余各点的坐标通过插值进行计算。

表面法向量许多应用程序中,网格上的各点都需要一个表面法向量。

它可以用来:(1)计算光照。

(2)进行背面剔除。

(3)模拟粒子在表面"弹跳"的效果。

(4)通过只考虑正面而加速碰撞检测。

表面法向量可能保存于三角形级或顶点级,或两者皆有。

三角形级法向量可以通过两向量叉乘的方法轻松获得,而顶点级法向量的计算则困难一些。

首先,应注意到顶点处其实是没有法向量定义的,因为此处网格表面不连续。

第二,三角网是对连续表面的逼近,所以我们实际想要的是连续表面的法向量。

根据产生三角网的方法,这种信息不一定现成可得。

如果网格是自动生成的,比如说从参数曲面上,则可以直接获得法向量。

若法向量没有提供,则必得有现成数据(顶点位置和三角形)生成。

一个技巧是平均相邻三角形的表面法向量并将结果标准化。

当然,这要求知道三角形法向量。

一般可以假设三角形顶点以顺时针列出,通过叉乘计算外表面的法向量。

如果顶点顺序不能假设时,可使用Glassner建议的方法。

相关主题