OpenGL: Чи можливо використовувати VAO без вказівки VBO


12

У всіх підручниках, які я можу знайти про VAO (Vertex Array Objects), вони показують, як їх використовувати, конфігуруючи атрибути вершин і прив’язуючи VBO (Vertex Buffer Object). Але я хочу створити VAO, який буде налаштований для набору VBO в поєднанні з фіксованим шейдером, де кожен буфер використовує однаковий шаблон даних (вершина, uv, колір тощо). Отже, я хочу створити один VAO для декількох VBO, які будуть намальовані за допомогою одного шейдера.

Я не міг знайти жодної демонстрації з цього приводу, тому вирішив спробувати. Але це не працює і вибивається під час glDrawArrayвиклику. Схоже, VBO не пов'язаний. Ось код, який я використовую:

Надання:

/* Prepare vertex attributes */
glBindVertexArrayOES(vao);

/* Upload the buffer to the GPU */
glBindBuffer(GL_ARRAY_BUFFER, pool->next());
glBufferSubData(GL_ARRAY_BUFFER, 0, parts * buffer.stride() * 6, buffer.getBuffer());

/* Draw the triangles */
glDrawArrays(GL_TRIANGLES, 0, parts * 6);

glBindVertexArrayOES(0);

Створення VAO:

glBindVertexArrayOES(vao);

glEnableVertexAttribArray(ls.position);
glVertexAttribPointer(ls.position, 2, GL_FLOAT, GL_FALSE, buffer.stride(), 0);

glEnableVertexAttribArray(ls.color);
glVertexAttribPointer(ls.color, 3, GL_FLOAT, GL_FALSE, buffer.stride(), GL_BUFFER_OFFSET(buffer.dataTypeSize * 2));

glBindVertexArrayOES(0);

Де lsпростий, structякий містить місця розташування атрибутів.

У частині візуалізації заміни glBindBufferта glBindVertexArrayOESнавколо також не працювали.

Отже, питання таке: чи можливо це зробити, або мені доведеться створити для кожного буфера VAO? І якщо мені доведеться створити VAO для кожного VBO, чи можливо оновити дані VBO, використовуючи glBufferSubDataв поєднанні з VAO?

Відповіді:


18

VAO не містять стану "glBindBuffer", за винятком стану GL_ELEMENT_ARRAY_BUFFERзв'язування 's. Що ви не розумієте, це те, що glBindBuffer(GL_ARRAY_BUFFER) нічого не робить . Що ж, це не робить нічого, що стосується візуалізації. Спробуй це; прямо перед викликом glDraw *, дзвоніть glBindBuffer(GL_ARRAY_BUFFER, 0); ваше відображення буде працювати чудово.

Те , як glVertexAttribPointerпрацює той , що він дивиться на те , що пов'язано з GL_ARRAY_BUFFER в той час glVertexAttribPointerназивається . Не під час візуалізації. Не пізніше. Саме в той самий момент. Він бере будь-який об'єкт буфера там і зберігає його в іншому фрагменті стану OpenGL, який інкапсульований у VAO.

Загалом у вас є два варіанти, один із них є новим і, мабуть, не повинен використовуватися в цей час.

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

Коли настає час візуалізації, ви можете надати частину вершин. glDrawArraysвимагає набору елементів для відображення, і ви можете налаштувати свої показники, glDrawElementsщоб зробити те саме. Крім того, ви можете використовувати glDrawElementsBaseVertexдля зміщення вершин , так що до кожного індексу додається зміщення. Це зміщення - кількість вершин перед цією вершиною у великому масиві.

Інша альтернатива - використовувати відносно нову систему поділу атрибутів формату, додану в GL 4.3. Це дозволить вам змінювати буфери, не скидаючи формат. Таким чином, ви зв'язали б один VAO, а потім просто замініть різні буфери за потребою glBindVertexBuffer. Це також доступно в ES 3.1.


1
Тепер драйвери NV GL4.3 мають повний реліз.
Максим Мінімус

Дуже дякую за пояснення способу роботи glVertexAttribPointer. Це було просвітницьким і пояснює, чому і як це працює.
Martijn Courteaux

5

VAO зберігає стан glVertexAttribPointer. Зміна VAO не впливає на поточний glBindBuffer, а також зміна glBindBuffer не впливає на VAO. На VAO впливає лише виклик glVertexAttribPointer, записуючи буфер, який використовується під час виклику.

Тож відповідь на ваше запитання - ні.

Один із варіантів, якщо ви хочете зменшити кількість об'єктів, - це помістити всі ваші сітчасті дані в одну велику VBO та вказати, де сіткові дані перебувають у VBO у виклику glDrawArrays, використовуючи аргументи 'first' та 'count'.


Усі статті в Інтернеті про те, що VAO показують, що зв'язування VAO автоматично зв'язує VBO. Отже, я думаю, що VAO - це конфігурація, яка містить як стани glVertexAttribPointer, так і стан glBindBuffer . І так, зв’язування VBO, коли VAO пов'язане, змінює VAO. Я говорю це, тому що я тестував це, і це ефективно робить. Звідки ця інформація береться?
Martijn Courteaux

2
@MartijnCourteaux: " Усі статті в Інтернеті про те, що VAO показують, що зв'язування VAO автоматично пов'язує VBO. Ні, вони не роблять. Специфікація OpenGL Wiki для вершин не відповідає. Дійсно, покажіть мені в Інтернеті одну статтю, в якій сказано, що будь-який glBindBufferстан, крім GL_ELEMENT_ARRAY_BUFFER цього, змінюється шляхом прив'язки VAO.
Нікол Болас

Інша відповідь добре пояснила, як працює метод glVertexAttribPointer. Він використовує VBO, пов'язаний на той час. Ти правий! Дякую, я зараз розумію.
Martijn Courteaux
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.