我什么时候应该使用OpenGL顶点的索引数组?

时间:2010-06-02 00:54:23

标签: arrays opengl vertex indexed

我试图清楚地知道何时应该使用带有gl [Multi] DrawElements等绘制的OpenGL顶点的索引数组,而不是我应该简单地使用连续的顶点数组,用gl绘制[多张] DrawArrays。

更新:我得到的回复中的共识是应该始终使用索引顶点。)

我已多次在这个问题上来回走动,所以我要概述我目前的理解,希望有人可以告诉我,我现在终于或多或少正确,或者指出我在哪里剩下的误解是。具体来说,我有三个结论,粗体。如果错误,请更正。

一个简单的例子是如果我的几何体由网格组成以形成曲面。在这种情况下,网格中间的顶点对于使用顶点的每个三角形都具有相同的属性(位置,法线,颜色,纹理坐标等)。

这使我得出结论:

1。对于接缝很少的几何体,索引数组是一个很大的胜利。

始终遵守规则1,除了:

对于非常“块状”的几何体,其中每个边都代表一个接缝,索引数组的好处不那么明显。以一个简单的立方体为例,虽然每个顶点用于三个不同的面,但我们不能在它们之间共享顶点,因为对于单个顶点,表面法线(以及可能的其他东西,如颜色和纹理合作) )每张脸都会有所不同。因此,我们需要在我们的数组中明确引入冗余顶点位置,以便可以使用不同的法线等多次使用相同的位置。这意味着索引数组的使用较少。

e.g。渲染立方体的单个面时:

 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时,我应该永远不要使用索引数组,而应该总是使用gl [Multi] DrawArrays。

更新:)回复表明这个结论是错误的。尽管索引不允许我们在这里减少数组的大小,但仍然应该使用它们,因为其他性能优势,如在评论中讨论)

规则2的唯一例外是:

当使用GL_TRIANGLES(而不是条带或扇形)时,一半的顶点仍然可以重复使用两次,具有相同的法线和颜色等,因为每个立方体面都呈现为两个独立的三角形。同样,对于同一个立方体面:

 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.

(据我所知,如果使用不同的类型,字节数可能会改变,具体数字只是为了说明。)

使用索引,我们可以稍微简化一下,给出:

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时,应始终使用索引数组,即使对于所有接缝的几何体也是如此。

如果错误,请以粗体更正我的结论。

1 个答案:

答案 0 :(得分:33)

  

由此我得出结论,当渲染所有接缝或大多数接缝的几何体时,当使用GL_TRIANGLE_STRIP或_FAN时,我应该永远不要使用索引数组,而应该总是使用gl [Multi] DrawArrays。

不,原因很简单。

您的结论是基于您分析了由两个三角形组成的单个四边形的事实。使用三角形扇形/条带绘制的这两个三角形不能使用索引数组进行简化。

但是试着想一下大的地形几何。使用三角形扇形/条形基元将每个地形块绘制为四边形。例如:

图中的每个三角形条带共同具有相邻三角形条带的所有顶点,并且使用索引可以压缩几何体定义,而不是为每个三角形条带重复顶点。


基本上,只要您可以将单个基元的大部分顶点与另一个基元共享,就可以使用索引绘制基本体(三角形,扇形和条形)。

共享信息可以节省信息传输带宽,但这并不是唯一的优势。实际上索引数组允许:

  • 避免同步属于同一“概念”顶点的信息,多次指定
  • 允许在单个顶点上执行相同的着色器操作,而不是多次执行,每个顶点重复一次。
  • 此外,结合使用三角形条/扇和索引允许应用程序压缩索引缓冲区,因为条带/扇形规范需要较少的索引(三角形每个面需要总共3个索引)。

正如您指定的那样,只要顶点不能与另一个重合顶点共享与其关联的每个信息(颜色,纹理坐标等),就不能使用索引数组。


为了完整起见,几何规范所需的信息大小并不是决定最佳渲染操作的唯一因素。

实际上,原始渲染的另一个基本因素是数据的缓存本地化。指定错误的几何数据(非交错缓冲区对象,长三角形条......)会导致大量缓存未命中,从而降低显卡性能。

为了优化渲染操作,顶点规范应以重新排序的方式重新排序,以最大的概率重用先前指定的顶点。通过这种方式,图形卡高速缓存行可以重用先前指定的顶点,而无需从内存中获取它们。