什么时候应该使用OpenGL顶点的索引数组?
我试图得到一个清晰的概念,当我应该使用索引的OpenGL顶点数组,用gl [Multi] DrawElements等绘制,而当我应该简单地使用连续的顶点数组,用gl [Multi] DrawArrays 。
( 更新:我收到的答复中的共识是,应该始终使用索引的顶点。)
我已经多次在这个问题上来回讨论,所以我将概述我目前的理解,希望有人能够告诉我,我现在终于或多或less地正确了,或者指出我剩下的误解是在哪里。 具体来说,我有三个结论,粗体。 如果他们错了,请纠正。
一个简单的例子是,如果我的几何形状由网格组成,形成曲面。 在这种情况下,网格中间的顶点对于使用该顶点的每个三angular形将具有相同的属性(位置,法线,颜色,纹理坐标等)。
这使我得出结论:
1.对于接缝较less的几何体,索引arrays是一个很大的胜利。
遵守规则1,除了:
对于非常“块状”的几何graphics,其中每个边代表一个接缝,索引数组的好处就不那么明显了。 以一个简单的立方体为例,虽然每个顶点被用于三个不同的面,我们不能共享它们之间的顶点,因为对于单个顶点,表面法线(以及可能的其他事物,比如颜色和纹理协调)在每张脸上都会有所不同。 因此,我们需要明确地将多余的顶点位置引入到我们的数组中,以便相同的位置可以使用多次不同的法线等。这意味着索引数组的用处不大。
例如渲染立方体的单个面时:
0 1 o---o |\ | | \ | | \| o---o 3 2
(这可以被孤立地考虑,因为这个面和所有相邻面之间的接缝意味着这些顶点之间的接缝都不能在面之间共享)
如果使用GL_TRIANGLE_FAN(或_STRIP)进行渲染,则可以渲染多维数据集的每个面:
verts = [v0, v1, v2, v3] colors = [c0, c0, c0, c0] normal = [n0, n0, n0, n0]
添加索引不允许我们简化这一点。
从这我得出结论:
2.当使用GL_TRIANGLE_STRIP或_FAN渲染几何graphics时,我不应该使用索引数组,而应该使用gl [Multi] DrawArrays。
( 更新:回复表明这个结论是错误的,即使指数不允许我们在这里减小数组的大小,但仍应该使用它们,因为其他性能好处,正如评论中所讨论的)
规则2唯一的例外是:
当使用GL_TRIANGLES(而不是条或者风扇)时,那么一半的顶点仍然可以重复使用两次,使用相同的法线和颜色等,因为每个立方体的面都被渲染成两个独立的三angular形。 同样,对于同一个单一的立方体面:
0 1 o---o |\ | | \ | | \| o---o 3 2
如果没有索引,使用GL_TRIANGLES,数组可能是这样的:
verts = [v0, v1, v2, v2, v3, v0] normals = [n0, n0, n0, n0, n0, n0] colors = [c0, c0, c0, c0, c0, c0]
由于顶点和法线通常是3个浮点数,颜色常常是3个字节,因此,对于每个立方体的面,都会给出:
verts = 6 * 3 floats = 18 floats normals = 6 * 3 floats = 18 floats colors = 6 * 3 bytes = 18 bytes = 36 floats and 18 bytes per cube face.
(我知道如果使用不同types的字节数可能会改变,确切的数字只是为了说明。)
有了索引,我们可以简化这一点,给:
verts = [v0, v1, v2, v3] (4 * 3 = 12 floats) normals = [n0, n0, n0, n0] (4 * 3 = 12 floats) colors = [c0, c0, c0, c0] (4 * 3 = 12 bytes) indices = [0, 1, 2, 2, 3, 0] (6 shorts) = 24 floats + 12 bytes, and maybe 6 shorts, per cube face.
看看在后一种情况下,顶点0和顶点2是如何使用两次,但只在每个顶点,法线和颜色数组中表示一次。 这听起来像是使用索引的一个小胜利,即使在每一个单一的几何边缘是一个接缝的极端情况下。
这使我得出结论:
3.使用GL_TRIANGLES时,应该总是使用索引数组,即使是几何都是接缝。
如果他们错了,请改正我的结论。
从这个我得出的结论是,当使用GL_TRIANGLE_STRIP或_FAN时,我不应该使用索引数组,而是应该总是使用gl [Multi] DrawArrays来渲染所有接缝或大部分接缝的几何体。
不,原因很简单。
你的结论是基于你分析由两个三angular形组成的单个四边形的事实。 使用三angular形风扇/条纹绘制的这两个三angular形不能使用索引数组进行简化。
但是试着去思考一个大的地形几何。 每个地形块被绘制为一个四边形,使用三angular形风扇/条形图元。 例如:
图中的每个三angular形带都有相邻三angular形带的所有顶点,使用索引可以压缩几何定义,而不是为每个三angular形带重复顶点。
基本上,使用索引绘制图元(三angular形,扇形和条形图)是有用的,只要您可以与另一个图元共享单个图元的大部分顶点。
共享信息可以节省信息传输带宽,但这不是唯一的优势。 实际上索引数组允许:
- 避免属于同一“概念”顶点的信息同步,多次指定
- 允许对单个顶点执行相同的着色器操作,而不是执行多次,每个顶点重复一次。
- 此外,由于条带/风扇规格要求较less的索引(三angular形总是需要每个面的3个索引),所以结合使用三angular形条带/风扇和索引允许应用程序压缩索引缓冲区。
按照您的指定,索引数组无法用于每个顶点无法共享与其相关的所有信息(颜色,纹理坐标等)与另一个重合的顶点。
只是为了完整性,几何规格所需的信息的大小并不是决定最佳渲染操作的唯一因素。
事实上,原始渲染的另一个基本因素是数据的caching本地化。 严格指定的几何数据(非交叉缓冲区对象,长三angular形条…)会导致大量高速caching未命中,从而降低graphics卡的性能。
为了优化渲染操作,顶点规范应该以重用先前指定顶点的方式进行重新sorting,其概率最高。 以这种方式,graphics卡caching线可以重新使用先前指定的顶点而不从存储器中取出它们。