¿Cuándo debo usar matrices indexadas de vértices de OpenGL?


Estoy tratando de tener una idea clara de cuándo debo usar matrices indexadas de vértices de OpenGL, dibujadas con elementos de dibujo gl[Multi]y similares, versus cuando simplemente debo usar matrices contiguas de vértices, dibujadas con elementos de dibujo gl[Multi].

(Actualización: El consenso en las respuestas que obtuve es que uno siempre debe usar vértices indexados.)

He ido y venido sobre este tema varias veces, así que voy a esbozar mi entendimiento actual, con la esperanza de alguien puede decirme que finalmente estoy más o menos correcto, o bien señalar dónde están mis malentendidos restantes. Concretamente, tengo tres conclusiones, en negrita. Por favor corríjalos si están equivocados.

Un caso simple es si mi geometría consiste en mallas para formar superficies curvas. En este caso, los vértices en el centro de la malla tendrán atributos idénticos (posición, normal, color, textura coord, etc.) para cada triángulo que utiliza el vértice.

Esto me lleva para concluir que:

1. Para la geometría con pocas uniones, los arrays indexados son una gran victoria.

Siga siempre la regla 1, excepto:

Para la geometría que es muy 'blocky', en la que cada arista representa una costura, el beneficio de los arrays indexados es menos obvio. Para tomar un cubo simple como ejemplo, aunque cada vértice se utiliza en tres caras diferentes, no podemos compartir vértices entre ellos, porque para un solo vértice, las normales de superficie (y otras cosas posibles, como color y textura co-ord) diferirá en cada cara. Por lo tanto, necesitamos introducir explícitamente posiciones de vértices redundantes en nuestra matriz, de modo que la misma posición se pueda usar varias veces con diferentes normales, etc. Esto significa que los arrays indexados son de menos uso.

Por ejemplo, Al representar una sola cara de un cubo:

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

(esto se puede considerar de forma aislada, porque las costuras entre esta cara y todas las caras adyacentes significan que ninguno de estos vértices se puede compartir entre las caras)

Si renderizado usando GL_TRIANGLE_FAN (o _STRIP), entonces cada cara del cubo se puede renderizar así:

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

Agregar índices no nos permite simplificar esto.

De esto concluyo que:

2. Al representar geometría que es todas las costuras o mayormente costuras, cuando se usa GL_TRIANGLE_STRIP o _FAN, entonces nunca debería usar matrices indexadas, y en su lugar siempre debería usar gl [Multi]drawArrays.

(Actualización: Las respuestas indican que esta conclusión es errónea. Incluso aunque los índices no nos permiten reducir el tamaño de los arrays aquí, aún deben usarse debido a otros beneficios de rendimiento, como se discute en los comentarios)

La única excepción a la regla 2 es:

Cuando se usan GL_TRIANGLES (en lugar de tiras o ventiladores), entonces la mitad de los vértices todavía se pueden reutilizar dos veces, con normales y colores idénticos, etc., porque cada cara de cubo se representa como dos triángulos separados. Una vez más, para la misma cara de cubo individual:

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

Sin índices, usando GL_TRIANGLES, los arrays serían algo así como:

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

Dado que un vértice y una normal son a menudo 3 flotadores cada uno, y un color es a menudo 3 bytes, que da, para cada cara del cubo, sobre:

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.

(Entiendo que el número de bytes podría cambiar si se utilizan diferentes tipos, las cifras exactas son solo para ilustrar.)

Con los índices, podemos simplificar esto un poco, dando:

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.

Vea cómo en este último caso, los vértices 0 y 2 se usan dos veces, pero solo representado una vez en cada una de las matrices verts, normales y colors. Esto suena como una pequeña victoria para el uso de índices, incluso en el caso extremo de cada borde de la geometría es una costura.

Esto me lleva a concluir que:

3. Cuando se usan GL_TRIANGLES, siempre se deben usar arrays indexados, incluso para geometría que es todas las uniones.

Por favor corrija mis conclusiones en negrita si están equivocadas.

Author: Jonathan Hartley, 2010-06-02

1 answers

De esto concluyo que cuando se renderiza geometría que es todas las costuras o mayormente costuras, cuando se usa GL_TRIANGLE_STRIP o _FAN, entonces nunca debería usar matrices indexadas, y en su lugar siempre debería usar gl[Multi] drawArrays.

No, y la razón es bastante simple.

Su conclusión se basa en el hecho de que ha analizado un solo cuádruple compuesto por dos triángulos. Estos dos triángulos dibujados usando triángulo fan / strip no se pueden simplificar usando matrices indexadas.

Pero trate de pensar en una geometría de terreno grande. Cada bloque de terreno se dibuja como un quad, utilizando triángulo ventilador / tira primitiva. Por ejemplo:

Cada tira triangular en la figura tiene en común todos los vértices con tiras triangulares adyacentes, y el uso de índices permite comprimir la definición de geometría, en lugar de repetir vértices para cada tira triangular.


Básicamente, dibujar primitivas (triángulos, abanicos y tiras) usando índices es útil siempre que se puede compartir la mayoría de los vértices de un solo primitivo con otro.

Compartir la información permite ahorrar ancho de banda de transmisión de información, pero no es la única ventaja. Los arrays realmente indexados permiten:

  • Evitar la sincronización de la información perteneciente al mismo vértice "conceptual", especificado muchas veces
  • Permitir realizar la misma operación de sombreado en un solo vértice en lugar de ejecutar muchas veces, una para cada vértice duplicación.
  • Además, la combinación del uso de tiras triangulares/ventiladores e índices permite a la aplicación comprimir el búfer de índices, ya que la especificación de tiras/ventiladores requiere menos índices (un triángulo requiere siempre 3 índices para cada cara).

La matriz indexada no se puede usar, como se ha especificado, siempre que un vértice no pueda compartir toda la información asociada con él (color, coordenadas de textura, etc.) con otro vértice coincidente.


Solo por el bien de integridad, el tamaño de la información necesaria para la especificación de geometría no es el único factor que determina la operación de renderizado óptima.

De hecho, otro factor fundamental para el renderizado primitivo es la localización en caché de los datos. Datos de geometría mal especificados (objetos de búfer no intercalados, tiras triangulares largas...) causa una gran cantidad de errores de caché, degradando el rendimiento de la tarjeta gráfica.

Para optimizar la operación de renderizado, el vértice la especificación se reordenará de manera que se reutilicen los vértices previamente especificados, con la mayor probabilidad. De esta manera, la línea de caché de la tarjeta gráfica puede reutilizar vértices previamente especificados sin obtenerlos de la memoria.

 33
Author: Luca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 16:03:09