Що таке об'єкти вершинного масиву?


114

Я зараз починаю вивчати OpenGL з цього підручника: http://openglbook.com/the-book/
Я перейшов до розділу 2, де я малюю трикутник, і я розумію все, крім VAO (це акронім ОК?). У підручнику є такий код:

glGenVertexArrays(1, &VaoId);
glBindVertexArray(VaoId);

Хоча я розумію, що код необхідний, я не маю поняття, що він робить. Хоча я ніколи не використовую VaoId минулого цього моменту (крім його знищення), код не функціонує без нього. Я припускаю, що це тому, що це потрібно обов'язково пов'язати, але я не знаю чому. Чи точно цей код повинен бути частиною кожної програми OpenGL? Навчальний посібник пояснює VAO:

Об'єкт вершинного масиву (або VAO) - це об'єкт, який описує, як атрибути вершин зберігаються в об'єкті буферних вершин (або VBO). Це означає, що VAO - це не власне об'єкт, що зберігає дані вершин, а дескриптор даних вершин. Атрибути вершин можна описати функцією glVertexAttribPointer та двома її сестринськими функціями glVertexAttribIPointer та glVertexAttribLPointer, першу з яких ми вивчимо нижче.

Я не розумію, як VAO описує атрибути вершин. Я їх жодним чином не описав. Чи отримує вона інформацію з glVertexAttribPointer? Я здогадуюсь, це мусить бути. Чи VAO просто місце призначення інформації з glVertexAttribPointer?

Зі сторони, чи підручник, за яким я слідую, прийнятний? Чи є щось, на що я повинен стежити, чи краще навчальний посібник, який слід дотримуватися?

Відповіді:


100

"Об'єкт масиву вершини" приносить вам підкомітет OpenGL ARB для нерозумних імен.

Подумайте про це як про об’єкт геометрії. (Як давній програміст SGI Performer, я називаю їх геосетами.) Змінні екземпляри / члени об'єкта - це ваш покажчик вершини, звичайний вказівник, кольоровий покажчик, attrib N pointer, ...

Коли VAO вперше пов'язаний, ви призначаєте цих членів, зателефонувавши

glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer...;
glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer...;

і так далі. Які атрибути ввімкнено, а вказані вами покажчики зберігаються у VAO.

Після цього, коли ви знову зв’яжете VAO, усі ці атрибути та покажчики також стають актуальними. Отже, один glBindVertexArrayвиклик еквівалентний коду, який раніше потрібен для налаштування всіх атрибутів. Це зручно для передачі геометрії між функціями чи методами без необхідності створювати власні структури чи об’єкти.

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

Більше інформації у відповідь на запитання Патріка:

Типово для новоствореного VAO є те, що він порожній (AFAIK). Ніякої геометрії немає, навіть не вершини, тому якщо ви спробуєте намалювати її, ви отримаєте помилку OpenGL. Це досить розумно, як і в "ініціалізувати все до False / NULL / zero".

Вам потрібно лише glEnableClientStateтоді, коли ви налаштовуєте речі. VAO запам'ятовує стан увімкнення / вимкнення для кожного вказівника.

Так, VAO зберігатиме glEnableVertexAttribArrayі glVertexAttrib. Стара вершина, нормальна, кольорова, ... масиви - це те саме, що масиви атрибутів, вершина == # 0 тощо.


62
'"Об'єкт масиву Vertex" вам приносить підкомітет OpenGL ARB для нерозумних імен. " Так, така нерозумна назва для об'єкта, який зберігає прив'язки вершинного масиву .
Нікол Болас

2
Також, чи взагалі пов’язані ВАОglVertexAttribPointer
Патрік

2
Додайте трохи інформації про використання загальних атрибутів вершин для людей, які використовують основний профіль.
Оскар

8
@NicolBolas Краще ім'я буде VertexArrayMacroчи щось подібне.
бобобобо

7
@NicolBolas "Об'єкт масиву вершин" - жахлива назва. Йдеться про прив’язку даних до атрибутів . Йдеться не про масив вершин, як випливає з назви. Немає посилання на прив’язки або атрибути в імені, а оскільки "вершина масив" є самою відокремленою концепцією, це робить розуміння ще складніше. IMHO, "(Vertex) Attributes Binding Object" простіше зрозуміти. Навіть об’єкт геометрії краще: мені це не подобається, але принаймні він не перевантажений.
AkiRoss

8

Об'єкти Vertex Array - це макроси в програмах обробки текстів тощо. Хороший опис можна знайти тут .

Макроси просто запам’ятовують дії, які ви робили, такі як активувати цей атрибут, прив’язувати цей буфер тощо. Коли ви телефонуєте glBindVertexArray( yourVAOId ), він просто відтворюється ті прив'язки вказівника та прив'язки буфера.

Тож ваш наступний дзвінок для виклику використовує все, що було пов'язано VAO.

VAO не зберігає дані вершин . Ні. Дані вершин зберігаються в буфері вершин або в масиві клієнтської пам'яті.


19
-1: Вони не схожі на макроси. Якби вони були, то прив'язування нового VAO не відключать вершинні масиви, включені попереднім VAO, якщо тільки новий VAO не "записав", ви явно відключили ці масиви. VAO, як і всі об’єкти OpenGL, утримують стан , а не команди. Команди просто змінюють стан, але об'єкти встановлюються із встановленим станом за замовчуванням. Ось чому прив'язка новоствореного VAO завжди відключатиме всі атрибути.
Нікол Болас

6

Я завжди думаю про VAO як масив буферів даних, що використовується OpenGL. Використовуючи сучасний OpenGL, ви створите VAO та Vertex Buffer Objects.

введіть тут опис зображення

//vaoB is a buffer
glGenVertexArrays(1, vaoB); //creates one VAO
glBindVertexArray(vao.get(0));
glGenBuffers(vbo.length, vbo, 0); //vbo is a buffer
glBindVertexArray(vao.get(1));
glGenBuffers(vbo1.length, vbo1, 0); //vbo1 is a buffer
glBindVertexArray(vao.get(2));
glGenBuffers(vbo2.length, vbo2, 0); //vbo2 is a buffer

Наступний крок - прив’язання даних до буфера:

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER,vertBuf.limit()*4, vertBuf, GL_STATIC_DRAW); //vertf buf is a floatbuffer of vertices

На даний момент OpenGL бачить:

введіть тут опис зображення

Тепер ми можемо використовувати glVertexAttribPointer, щоб повідомити OpenGL, що представляють дані в буфері:

glBindBuffer(GL_ARRAY_BUFFER, 0); //bind VBO at 0
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); //each vertex has 3 components of size GL_FLOAT with 0 stride (space) between them and the first component starts at 0 (start of data)

введіть тут опис зображення

Тепер OpenGL має дані в буфері і знає, як дані організовані у вершини. Цей же процес може бути застосований до координат текстури тощо, але для координат текстури було б два значення.

glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER,coordBuf.limit()*4, coordBuf, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

Далі ви можете зв'язати текстуру та намалювати масиви, вам захочеться створити шейдер Vert і Frag, компілювати та приєднувати його до програми (сюди не включено).

glActiveTexture(textureID); //bind our texture
glBindTexture(GL_TEXTURE_2D, textureID);
glDrawArrays(GL_TRIANGLES,0,6); //in this case 6 indices are used for two triangles forming a square

5

VAO - це об'єкт, який представляє етап вибору вершини трубопроводу OpenGL і використовується для подачі вхідного вершинного шейдера.

Ви можете створити подібний об’єкт масиву вершин

GLuint vao;
glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);

Спочатку давайте простий приклад. Розглянемо такий вхідний параметр у коді шейдера

layout (location = 0) in vec4 offset; // input vertex attribute

Для заповнення цього атрибуту ми можемо використовувати

glVertexAttrib4fv(0, attrib); // updates the value of input attribute 0

Хоча об’єкт вершинного масиву зберігає для вас ці статичні значення атрибутів, він може зробити набагато більше.

Після створення об’єкта вершинного масиву ми можемо почати заповнювати його стан. Ми попросимо OpenGL автоматично заповнити його, використовуючи дані, що зберігаються в буферному об'єкті, який ми постачаємо. Кожен атрибут вершини отримує дані з буфера, пов'язаного з одним із декількох прив'язків вершинного буфера. Для цього ми використовуємо glVertexArrayAttribBinding(GLuint vao, GLuint attribindex, GLuint bindingindex). Також ми використовуємо glVertexArrayVertexBuffer()функцію прив’язки буфера до однієї з вершин вершинного буфера. Ми використовуємо glVertexArrayAttribFormat()функцію для опису компонування та формату даних, і, нарешті, вмикаємо автоматичне заповнення атрибуту за допомогою виклику glEnableVertexAttribArray().

Якщо ввімкнено атрибут вершини, OpenGL буде передавати дані у вершину шейдера на основі формату та інформації про місцезнаходження, яку ви надали glVertexArrayVertexBuffer()та glVertexArrayAttribFormat(). Коли атрибут вимкнено, вершинному шейдеру буде надана статична інформація, до якої ви надаєте дзвінок glVertexAttrib*().

// First, bind a vertex buffer to the VAO
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vmath::vec4));

// Now, describe the data to OpenGL, tell it where it is, and turn on automatic
// vertex fetching for the specified attribute
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, 0);

glEnableVertexArrayAttrib(vao, 0);

І код у шейдері

layout (location = 0) in vec4 position;

Адже вам потрібно зателефонувати glDeleteVertexArrays(1, &vao).


Ви можете прочитати OpenGL SuperBible, щоб краще зрозуміти це.


3
Добре бачити людей, які рекламують використання OpenGL у стилі DSA.
Нікол Болас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.