Кожен 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 - це більше, ніж просто економія пам'яті, що є наївним способом її вимірювання. Існує потенціал для збереження пам'яті, де вершини можна повторно використовувати, оскільки індекс, як правило, менший за вершину (тому навіть якщо у вас є багато індексів на балансі, вони будуть меншими), але до інших переваг можна віднести:
Скорочена кількість викликів при розіграші. Кожен виклик нічиї вимагає певних накладних витрат із стану перевірки, налаштування речей тощо, і значна частина цих накладних витрат відбувається на стороні процесора. Скорочуючи кількість дзвінків на виклик, ми уникаємо великої частини цих витрат.
Повторне використання вершин. Це набагато більше, ніж просто економія пам’яті. Ваш GPU, ймовірно, має апаратний кеш вершин, де можна зберігати нещодавно перетворені вершини; якщо знову з'явиться та сама вершина, і якщо вона знаходиться в кеші, її можна повторно використовувати з кеша, а не перетворювати її знову. Ваша апаратура перевірятиме кеш, порівнюючи індекси, тому в умовах OpenGL єдиний спосіб отримати кеш - це використовувати glDrawElements.
Отже, щоб відповісти на ваші конкретні запитання:
як glDrawElements міг зберігати дзвінки дзвінка ...? У прикладі, який ви використовуєте, це не так. Кожен має один розіграш. Як я обговорював вище, цей приклад є дуже поганим для порівняння двох.
як за допомогою glDrawElements заощадити простір ...? Тому що індекси менші за вершини. 16-розрядний індекс - два байти, вершина позиції / кольору / текокоординату - 24 байти. 6 вершин - 144 байти, 4 вершини плюс 6 індексів - 108 байт.
У разі малювання квадрата з 2 трикутників ...? Один і один. Виклик glDraw * - це один дзвінок звороту, кількість використаних вершин або індексів не має значення для цього вимірювання. Але мушу ще раз підкреслити, це дуже поганий приклад порівняння цих двох.
Нарешті, і лише щоб трохи ускладнити справи, в той час як glDrawElements з трикутниками є оптимальним шляхом для настільних графічних процесорів, для мобільних пристроїв це може бути дуже різним. Деякі мобільні графічні процесори, можливо, віддадуть перевагу glDrawArrays з GL_TRIANGLE_STRIP (у цьому випадку ви додасте вироджені трикутники, щоб об'єднати примітиви), і я навіть не торкався більш складних тем, таких як примітивний перезапуск або мультиварка.