Різниця в glDrawArrays та glDrawElements


12

Освіжуючи свою думку на OpenGL ES, я натрапив на glDrawArraysта glDrawElements.

Я розумію, як вони використовуються, і начебто розумію, чому вони різні.

Я, здається, не розумію, це те, що я не бачу, як glDrawElementsможна зберегти дзвінки дзвінка ( збереження дзвінків дзвінків - це опис, про який згадується більшість прочитаних книг, отже, тут я згадую про це).

Уявіть простий сценарій, у якому я намагався намалювати квадрат, використовуючи 2 трикутники.

Мені потрібно мати набір з 6 вершин, які використовують glDrawArraysпід час використання glDrawElements, мені знадобиться лише 4 на додаток до масиву індексів, який містить 6 елементів.

З огляду на сказане, ось що я не розумію:

  1. як можна glDrawElementsзберегти дзвінки з розіграшу, якщо він все ще потребує використання масиву індексів (6 індексів у випадку квадрата) для індексації у моєму вершинному масиві, який мав 4 елементи (6 разів)? Іншими словами, чи означає glDrawElementsце, що все-таки потрібно мати 6 розмовних дзвінків так само glDrawArrays?
  2. як би використовувати glDrawElementsекономію простору, якщо все-таки потрібно мати 2 масиви, а саме: один для вершин і один для індексів?
  3. У випадку малювання квадрата з 2 трикутників, для простоти, скільки дзвінків для малювання glDrawElements(4 елемента у вершинній масиві та 6 елементів у масиві індексів) та glDrawArrays(6 елементів лише у вершинній масиві) потрібно індивідуально?

Дякую.

Відповіді:


16

Кожен 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.


Отже, щоб відповісти на ваші конкретні запитання:

  1. як glDrawElements міг зберігати дзвінки дзвінка ...? У прикладі, який ви використовуєте, це не так. Кожен має один розіграш. Як я обговорював вище, цей приклад є дуже поганим для порівняння двох.

  2. як за допомогою glDrawElements заощадити простір ...? Тому що індекси менші за вершини. 16-розрядний індекс - два байти, вершина позиції / кольору / текокоординату - 24 байти. 6 вершин - 144 байти, 4 вершини плюс 6 індексів - 108 байт.

  3. У разі малювання квадрата з 2 трикутників ...? Один і один. Виклик glDraw * - це один дзвінок звороту, кількість використаних вершин або індексів не має значення для цього вимірювання. Але мушу ще раз підкреслити, це дуже поганий приклад порівняння цих двох.


Нарешті, і лише щоб трохи ускладнити справи, в той час як glDrawElements з трикутниками є оптимальним шляхом для настільних графічних процесорів, для мобільних пристроїв це може бути дуже різним. Деякі мобільні графічні процесори, можливо, віддадуть перевагу glDrawArrays з GL_TRIANGLE_STRIP (у цьому випадку ви додасте вироджені трикутники, щоб об'єднати примітиви), і я навіть не торкався більш складних тем, таких як примітивний перезапуск або мультиварка.


Велике спасибі за ваш відгук; Я просто небагато часу читаю те, що ви поділилися. Просто хотів повідомити, що я визнав вашу відповідь. Знову дякую.
Unheilig

У вашому прикладі перетворення 6 дзвінків DrawTriangleFans та DrawTriangleStrips до 1 одиничного виклику DrawTriangles. Чи справді це покращує деяку ефективність? Наскільки я розумію, малювання трикутної смужки, що складається з 100 трикутників, набагато ефективніше, ніж малювання 100 трикутників окремо, і вигода легко компенсує будь-який штраф, який виник у випадку використання 6 функціональних викликів, а не 1.
Самуель Лі

@SamuelLi 6-на-1 не буде величезним вдосконаленням, він лише призначений для ілюстрації принципу. Крім того, як я вже зазначив, смужки, як правило, не є перемогою продуктивності за індексованими списками на апаратному забезпеченні робочого столу після 1998 року. Перевірте дату на будь-якому документі, який радить використовувати смужки.
Максим Мінімус

Зрозумів, дякую за роз’яснення! @MaximusMinimus
Самуель Лі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.