Я пытаюсь понять, когда мне следует использовать индексированные массивы вершин OpenGL, нарисованные с помощью gl [Multi] DrawElements и т.п., по сравнению с тем, когда я должен просто использовать непрерывные массивы вершин, нарисованные с помощью gl [Multi] DrawArrays .
(Обновление: все ответы, которые я получил, сводятся к тому, что всегда следует использовать индексированные вершины.)
Я возвращался к этому вопросу несколько раз, поэтому я собираюсь обрисовать свое текущее понимание в надежде, что кто-то может либо сказать мне, что я теперь, наконец, более или менее прав, либо указать, где мои оставшиеся недоразумения . В частности, у меня три вывода, выделенные жирным шрифтом. Пожалуйста, исправьте их, если они ошибочны.
Один простой случай - моя геометрия состоит из сеток, образующих изогнутые поверхности. В этом случае вершины в середине меша будут иметь одинаковые атрибуты (положение, нормаль, цвет, координаты текстуры и т. Д.) Для каждого треугольника, использующего вершину.
Это подводит меня к выводу, что:
1. Для геометрии с небольшим количеством швов большие преимущества имеют индексированные массивы.
Всегда соблюдайте правило 1, за исключением:
Для очень «блочной» геометрии, в которой каждое ребро представляет собой шов, преимущество индексированных массивов менее очевидно. Чтобы взять простой куб в качестве примера, хотя каждая вершина используется в трех разных гранях, мы не можем разделять вершины между ними, потому что для одной вершины нормали поверхности (и возможные другие вещи, такие как цвет и координаты текстуры ) будет отличаться на каждой грани. Следовательно, нам необходимо явно ввести избыточные позиции вершин в наш массив, чтобы одна и та же позиция могла использоваться несколько раз с разными нормалями и т. Д. Это означает, что индексированные массивы менее полезны.
например При рендеринге одной грани куба:
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 байта, это дает для каждой грани куба примерно:
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 всегда следует использовать индексированные массивы, даже для геометрии, состоящей из швов.
Пожалуйста, исправьте мои выводы жирным шрифтом, если они ошибочны.