Деяка термінологія дещо відхилена:
- A
Vertex Array
- це просто масив (як правило, а float[]
), який містить дані вершин. Це не потрібно ні до чого прив'язувати. Не плутати з Vertex Array Object
aO або VAO, про що я перейду пізніше
- A
Buffer Object
, яку зазвичай називають Vertex Buffer Object
при зберіганні вершин або коротким VBO - це те, що ви називаєте просто a Buffer
.
- Ніщо не зберігається назад у масиві вершин,
glVertexAttribPointer
працює точно так само glVertexPointer
або glTexCoordPointer
працює, просто замість іменованих атрибутів ви отримуєте число, яке вказує ваш власний атрибут. Ви передаєте це значення як index
. Усі ваші glVertexAttribPointer
дзвінки стають в чергу на наступний раз, коли ви телефонуєте glDrawArrays
або glDrawElements
. Якщо у вас пов’язаний VAO, VAO зберігатиме налаштування для всіх ваших атрибутів.
Основна проблема полягає в тому, що ви плутаєте атрибути вершин з VAO. Атрибути вершин - це лише новий спосіб визначення вершин, текстових рядків, нормалів тощо для малювання. Стан магазину VAO. Спершу я поясню, як малювання працює з атрибутами вершини, а потім поясню, як можна скоротити кількість викликів методу за допомогою VAO:
- Ви повинні ввімкнути атрибут, перш ніж зможете використовувати його в шейдері. Наприклад, якщо ви хочете надіслати вершини шейдеру, ви, швидше за все, надішлете їх як перший атрибут, 0. Тому перед тим, як відтворити, вам потрібно увімкнути його за допомогою
glEnableVertexAttribArray(0);
.
- Тепер, коли атрибут увімкнено, вам потрібно визначити дані, які він буде використовувати. Для цього вам потрібно прив'язати ваш VBO -
glBindBuffer(GL_ARRAY_BUFFER, myBuffer);
.
- І тепер ми можемо визначити атрибут -
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
. У порядку параметра: 0 - це атрибут, який ви визначаєте, 3 - розмір кожної вершини, GL_FLOAT
це тип, GL_FALSE
означає не нормалізувати кожну вершину, останні 2 нулі означають, що на вершинах немає кроку або зміщення.
- Намалюйте щось із цим -
glDrawArrays(GL_TRIANGLES, 0, 6);
- Наступне, що ви намалюєте, може не використовувати атрибут 0 (реально це буде, але це приклад), тому ми можемо його відключити -
glDisableVertexAttribArray(0);
Оберніть це у glUseProgram()
дзвінки, і у вас є система візуалізації, яка правильно працює з шейдерами. Припустимо, у вас є 5 різних атрибутів, вершин, текстових координат, нормалей, кольору та координат світлової карти. Перш за все, ви б здійснювали один glVertexAttribPointer
виклик для кожного з цих атрибутів, і вам слід було б заздалегідь увімкнути всі атрибути. Скажімо, ви визначаєте атрибути 0-4 так, як я їх перелічую. Ви б увімкнули їх усіх так:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
І тоді вам доведеться зв'язати різні РВО для кожного атрибута (якщо не зберігати їх все в одному VBO і використання зсувам / крок), то вам необхідно зробити 5 різних glVertexAttribPointer
викликів, від glVertexAttribPointer(0,...);
до glVertexAttribPointer(4,...);
вершин , до Lightmap координат відповідно.
Будемо сподіватися, що одна система має сенс. Тепер я перейду до VAO, щоб пояснити, як використовувати їх для скорочення кількості викликів методів під час здійснення цього виду візуалізації. Зауважте, що використовувати VAO не потрібно.
A Vertex Array Object
або VAO використовується для зберігання стану всіх glVertexAttribPointer
дзвінків та VBO, націлених під час кожного glVertexAttribPointer
дзвінка.
Ви генеруєте такий із викликом до glGenVertexArrays
. Щоб зберегти все необхідне в VAO, зв’яжіть його glBindVertexArray
, а потім здійсніть повний дзвінок . Усі дзвінки прив'язки притягування перехоплюються і зберігаються VAO. Ви можете відв’язати VAO за допомогоюglBindVertexArray(0);
Тепер , коли ви хочете намалювати об'єкт, вам не потрібно повторно закличуть все VBÖ прив'язки або glVertexAttribPointer
дзвінки, вам просто потрібно зв'язати з ВАО glBindVertexArray
потім зателефонувати glDrawArrays
або glDrawElements
і ви будете малювати одне і те ж , як якщо б вас робили всі ці виклики методів. Можливо, ви також захочете відв’язати VAO пізніше.
Після того, як ви від'єднаєте VAO, весь стан повертається до того, яким він був до того, як ви зв’язали VAO. Я не впевнений, чи зберігаються будь-які зміни, які ви робите під час зв’язку VAO, але це легко можна зрозуміти за допомогою тестової програми. Я думаю, ви можете вважати glBindVertexArray(0);
прив'язкою до "за замовчуванням" VAO ...
Оновлення: Хтось звернув до мене увагу необхідності фактичного розіграшу дзвінка. Як виявляється, насправді вам не потрібно робити ПОВНИЙ виклик витягування при налаштуванні VAO, а лише всі пов’язувальні матеріали. Не знаю, чому я вважав це необхідним раніше, але це виправлено зараз.