简体   繁体   English

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

[英]When should I use indexed arrays of OpenGL vertices?

I'm trying to get a clear idea of when I should be using indexed arrays of OpenGL vertices, drawn with gl[Multi]DrawElements and the like, versus when I should simply use contiguous arrays of vertices, drawn with gl[Multi]DrawArrays. 我试图清楚地知道何时应该使用带有gl [Multi] DrawElements等绘制的OpenGL顶点的索引数组,而不是我应该简单地使用连续的顶点数组,用gl [Multi] DrawArrays绘制。

( Update: The consensus in the replies I got is that one should always be using indexed vertices.) 更新:我得到的回复中的共识是,应该始终使用索引顶点。)

I have gone back and forth on this issue several times, so I'm going to outline my current understanding, in the hopes someone can either tell me I'm now finally more or less correct, or else point out where my remaining misunderstandings are. 我已经多次在这个问题上来回走动了,所以我将概述我目前的理解,希望有人可以告诉我,我现在终于或多或少正确,或者指出我剩下的误解在哪里。 Specifically, I have three conclusions, in bold. 具体来说,我有三个结论,粗体。 Please correct them if they are wrong. 如果错误请纠正。

One simple case is if my geometry consists of meshes to form curved surfaces. 一个简单的例子是如果我的几何体由网格组成以形成曲面。 In this case, the vertices in the middle of the mesh will have identical attributes (position, normal, color, texture coord, etc) for every triangle which uses the vertex. 在这种情况下,网格中间的顶点对于使用顶点的每个三角形将具有相同的属性(位置,法线,颜色,纹理坐标等)。

This leads me to conclude that: 这使我得出结论:

1. For geometry with few seams, indexed arrays are a big win. 对于接缝很少的几何体,索引数组是一个巨大的胜利。

Follow rule 1 always, except: 始终遵循规则1,除了:

For geometry that is very 'blocky', in which every edge represents a seam, the benefit of indexed arrays is less obvious. 对于非常“块状”的几何体,其中每个边都代表一个接缝,索引数组的好处不那么明显。 To take a simple cube as an example, although each vertex is used in three different faces, we can't share vertices between them, because for a single vertex, the surface normals (and possible other things, like color and texture co-ord) will differ on each face. 以一个简单的立方体为例,虽然每个顶点用于三个不同的面,但我们不能在它们之间共享顶点,因为对于单个顶点,表面法线(以及可能的其他东西,如颜色和纹理合作) )每张脸都会有所不同。 Hence we need to explicitly introduce redundant vertex positions into our array, so that the same position can be used several times with different normals, etc. This means that indexed arrays are of less use. 因此,我们需要明确地将冗余顶点位置引入到我们的数组中,以便可以使用不同的法线等多次使用相同的位置。这意味着索引数组的使用较少。

eg When rendering a single face of a cube: 例如,渲染立方体的单个面时:

 0     1
  o---o
  |\  |
  | \ |
  |  \|
  o---o
 3     2

(this can be considered in isolation, because the seams between this face and all adjacent faces mean than none of these vertices can be shared between faces) (这可以单独考虑,因为这个面和所有相邻面之间的接缝意味着这些顶点之间不能共享这些顶点)

if rendering using GL_TRIANGLE_FAN (or _STRIP), then each face of the cube can be rendered thus: 如果使用GL_TRIANGLE_FAN(或_STRIP)进行渲染,则可以渲染立方体的每个面:

verts  = [v0, v1, v2, v3]
colors = [c0, c0, c0, c0]
normal = [n0, n0, n0, n0]

Adding indices does not allow us to simplify this. 添加索引不允许我们简化此操作。

From this I conclude that: 由此我得出结论:

2. When rendering geometry which is all seams or mostly seams, when using GL_TRIANGLE_STRIP or _FAN, then I should never use indexed arrays, and should instead always use gl[Multi]DrawArrays. 2.当渲染所有接缝或大多数接缝的几何体时,当使用GL_TRIANGLE_STRIP或_FAN时,我应该永远不要使用索引数组,而应该总是使用gl [Multi] DrawArrays。

( Update: Replies indicate that this conclusion is wrong. Even though indices don't allow us to reduce the size of the arrays here, they should still be used because of other performance benefits, as discussed in the comments) 更新:回复表明这个结论是错误的。即使索引不允许我们在这里减小数组的大小,仍然应该使用它们,因为其他性能优势,如评论中所讨论的)

The only exception to rule 2 is: 规则2的唯一例外是:

When using GL_TRIANGLES (instead of strips or fans), then half of the vertices can still be re-used twice, with identical normals and colors, etc, because each cube face is rendered as two separate triangles. 当使用GL_TRIANGLES(而不是条带或扇形)时,一半的顶点仍然可以重复使用两次,具有相同的法线和颜色等,因为每个立方体面都呈现为两个独立的三角形。 Again, for the same single cube face: 同样,对于相同的单个立方体面:

 0     1
  o---o
  |\  |
  | \ |
  |  \|
  o---o
 3     2

Without indices, using GL_TRIANGLES, the arrays would be something like: 没有索引,使用GL_TRIANGLES,数组将是这样的:

verts =   [v0, v1, v2,  v2, v3, v0]
normals = [n0, n0, n0,  n0, n0, n0]
colors =  [c0, c0, c0,  c0, c0, c0]

Since a vertex and a normal are often 3 floats each, and a color is often 3 bytes, that gives, for each cube face, about: 由于顶点和法线通常每个都有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.

(I understand the number of bytes might change if different types are used, the exact figures are just for illustration.) (我知道如果使用不同的类型,字节数可能会改变,具体数字只是为了说明。)

With indices, we can simplify this a little, giving: 有了索引,我们可以简化一下,给出:

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.

See how in the latter case, vertices 0 and 2 are used twice, but only represented once in each of the verts, normals and colors arrays. 看看在后一种情况下,顶点0和2是如何使用两次的,但在每个顶点,法线和颜色数组中只表示一次。 This sounds like a small win for using indices, even in the extreme case of every single geometry edge being a seam. 这听起来像使用索引的小胜利,即使在每个几何边缘都是接缝的极端情况下也是如此。

This leads me to conclude that: 这使我得出结论:

3. When using GL_TRIANGLES, one should always use indexed arrays, even for geometry which is all seams. 3.使用GL_TRIANGLES时,应始终使用索引数组,即使对于所有接缝的几何体也是如此。

Please correct my conclusions in bold if they are wrong. 如果错误,请以粗体更正我的结论。

From this I conclude that when rendering geometry which is all seams or mostly seams, when using GL_TRIANGLE_STRIP or _FAN, then I should never use indexed arrays, and should instead always use gl[Multi]DrawArrays. 由此我得出结论,当渲染所有接缝或大多数接缝的几何体时,当使用GL_TRIANGLE_STRIP或_FAN时,我应该永远不要使用索引数组,而应该总是使用gl [Multi] DrawArrays。

No, and the reason is quite simple. 不,原因很简单。

Your conclusion is based on the fact you have analysed a single quad composed by two triangles. 您的结论是基于您分析了由两个三角形组成的单个四边形的事实。 These two triangles drawn using triangle fan/strip cannot be simplified using indexed arrays. 使用三角形扇形/条带绘制的这两个三角形不能使用索引数组进行简化。

But try to think about a large terrain geometry. 但是试着想一下大的地形几何。 Each terrain block is drawn as a quad, using triangle fan/strip primitive. 使用三角形扇形/条形基元将每个地形块绘制为四边形。 For example: 例如:

Each triangle strip in the figure has in common all vertices with adjacent triangle strips, and using indices allow to compress the geometry definition, instead of repeating vertices for each triangle strip. 图中的每个三角形条带共同具有相邻三角形条带的所有顶点,并且使用索引允许压缩几何体定义,而不是为每个三角形条带重复顶点。


Basically, drawing primitives (triangles, fans and strips) using indices are usefull whenever you can share most of vertices of a single primitive with another one. 基本上,只要您可以将单个基元的大多数顶点与另一个基元共享,就可以使用索引绘制基本体(三角形,扇形和条形)。

Sharing the information allow to save information transmission bandwidth, but it is not the only advantage. 共享信息可以节省信息传输带宽,但这并不是唯一的优势。 Actually indexed arrays allow: 实际上索引数组允许:

  • Avoid the synchronization of the information belonging to the same "conceptual" vertex, specified many times 避免同步多次指定属于同一“概念”顶点的信息
  • Allow to perform the same shader operation on a single vertex instead executing many times, one for each vertex duplication. 允许在单个顶点上执行相同的着色器操作,而不是多次执行,每个顶点重复一次。
  • Furthermore, combining the use of triangle strips/fans and indices allow the application to compress the indices buffer, since the strip/fan specification requires less indices (a triangle requires always 3 indices for each face). 此外,结合三角形条带/扇形和索引的使用允许应用程序压缩索引缓冲区,因为条带/扇形规范需要较少的索引(三角形每个面需要总共3个索引)。

Indexed array cannot be used, as you have specified, whenever a vertex cannot share every information associated with it (color, texture coords and so on) with another coincident vertex. 正如您指定的那样,只要顶点不能与另一个重合顶点共享与其关联的每个信息(颜色,纹理坐标等),就不能使用索引数组。


Just for the sake of completeness, the size of the information necessary for the geometry specification is not the only factor wich determine the optimal rendering operation. 仅仅为了完整性,几何规范所需的信息大小不是决定最佳渲染操作的唯一因素。

Infact, another fundamental factor for primitive rendering is the cache localization of the data. 实际上,原始渲染的另一个基本因素是数据的缓存本地化。 Badly specified geometry data (non interleaved buffer objects, long triangle strips...) causes a lot of cache misses, degrading graphic card performance. 指定错误的几何数据(非交错缓冲区对象,长三角形条带......)会导致大量缓存未命中,从而降低显卡性能。

In order to optimize the rendering operation, the vertex specification shall be reordered in a way to reuse previously specified vertices, with the most probability. 为了优化渲染操作,顶点规范应以重新排序的方式重新排序,以最大的概率重用先前指定的顶点。 In such way, the graphic card cache line can reuse previously specified vertices without fetching them from memory. 以这种方式,图形卡高速缓存行可以重用先前指定的顶点而无需从存储器中取出它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM