Каждый glDraw * является вызовом отрисовки.
1 glDrawArrays - это 1 вызов на ничью.
1 glDrawElements - это 1 вызов ничьей.
Неважно (что касается количества вызовов отрисовки), сколько вершин или индексов вы используете, 1 glDraw * - это 1 вызов отрисовки.
Простые случаи рисования четырехугольников (при условии, что в используемой вами версии GL не удалены четырехугольники) или треугольники не являются хорошим примером для их сравнения, поскольку список четырехугольников или список треугольников можно нарисовать с помощью одного вызова любого из них, и glDrawArrays будет казаться более эффективным, потому что у него нет дополнительных затрат на индексацию.
Давайте рассмотрим немного более сложный случай, но представительный для более реального сценария. Представьте, что у вас есть модель, состоящая из нескольких треугольных полос и вееров:
glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);
В этом примере использование glDrawArrays дает вам в общей сложности 6 вызовов отрисовки для модели. Тем не менее, как полосы, так и вентиляторы могут быть легко преобразованы в индексированные треугольники, поэтому добавьте индексы, и это станет:
glDrawElements (GL_TRIANGLES, .....);
Это один розыгрыш для всей модели.
Преимущества glDrawElements по сравнению с glDrawArrays заключаются не только в экономии памяти, что является наивным способом измерения. Существует потенциал для экономии памяти, когда вершины можно использовать повторно, потому что индекс обычно меньше вершины (поэтому, даже если у вас много индексов в балансе, они будут меньше), но другие преимущества включают в себя:
Уменьшено количество вызовов отрисовки. Каждый вызов отрисовки влечет за собой некоторые накладные расходы от проверки состояния, настройки и т. Д., И большая часть этих накладных расходов происходит на стороне ЦП. Сокращая количество вызовов отрисовки, мы избегаем значительной части этих накладных расходов.
Повторное использование вершин. Это гораздо больше, чем просто экономия памяти. Ваш графический процессор, скорее всего, имеет аппаратный кеш вершин, в котором могут храниться недавно преобразованные вершины; если та же самая вершина входит снова, и если она находится в кеше, ее можно повторно использовать из кеша, вместо того, чтобы снова преобразовывать. Ваше оборудование будет проверять кеш путем сравнения индексов, поэтому в терминах OpenGL единственный способ использовать кеш - использовать glDrawElements.
Итак, чтобы ответить на ваши конкретные вопросы:
Как glDrawElements может сохранить вызовы отрисовки ...? В примере, который вы используете, это не так. У каждого есть один колл-дро. Как я уже говорил выше, этот пример очень плох для сравнения.
Как с помощью glDrawElements сэкономить место ...? Потому что индексы меньше, чем вершины. 16-битный индекс составляет два байта, вершина позиции / цвета / текстовой координаты составляет 24 байта. 6 вершин - 144 байта, 4 вершины плюс 6 индексов - 108 байтов.
В случае рисования квадрата из 2-х треугольников ...? Один и один. Вызов glDraw * - это один вызов отрисовки, количество используемых вершин или индексов не имеет значения для этого измерения. Но я должен еще раз подчеркнуть, что это очень плохой пример для сравнения двух.
И, наконец, если немного усложнить ситуацию, в то время как glDrawElements с треугольниками - это оптимальный путь для настольных графических процессоров, для мобильных устройств он может сильно отличаться. Некоторые мобильные графические процессоры могут предпочесть glDrawArrays с GL_TRIANGLE_STRIP (в этом случае вы бы добавили вырожденные треугольники для объединения примитивов), и я даже не затрагивал более сложные темы, такие как перезапуск примитивов или мульти-рисование.