Какое состояние хранится в объекте Vertex Array (VAO) OpenGL и как правильно использовать VAO?

25

Мне было интересно, какое состояние хранится в OpenGL VAO. Я понял, что VAO содержит состояние, связанное со спецификациями вершин буферизованных вершин (какие атрибуты находятся в буферах и какие буферы связаны, ...). Чтобы лучше понять правильное использование VAO, я бы хотел точно знать, в каком состоянии они находятся.


Как я предполагаю, что VAO следует использовать

Из простых примеров я понял, что правильное использование VAO заключается в следующем:

Настроить

Generate VAO
BindVAO
---- Specify vertex attributes
---- Generate VBO's
---- BindVBO's
-------- Buffer vertex data in VBO's
---- Unbind VBO's
Unbind VAO

оказание

Bind VAO
---- Draw
Unbind VAO

Исходя из этого, я предполагаю, что по крайней мере привязки буфера вершин и спецификации атрибутов вершин хранятся в VAO. Однако я не уверен, как этот шаблон использования распространяется на ситуации, когда (несколько) текстур и (несколько) шейдерных программ вступают в игру. Сохраняется ли активная шейдерная программа в VAO? И хранятся ли в VAO привязки текстур (с их настройками выборки / обтекания )? То же самое для униформы ?


Поэтому мои вопросы таковы:

  • Какое точное состояние хранится в OpenGL VAO ? (Привязки VBO, спецификации атрибутов, активная программа шейдеров, привязки текстур, настройки выборки / обтекания текстур, униформа ...?)
  • Как правильно использовать VAO в более сложной настройке рендеринга, в которой участвуют (несколько) текстур с соответствующими настройками выборки / обтекания, (несколько) шейдерных программ и униформ?
Желе ван Кампен
источник
1
VAO хранит данные о расположении атрибутов вершин. Он также хранит идентификаторы VBO, в которых содержатся эти атрибуты. Вам не нужно связывать VBO при рисовании чего-либо, вам нужно связать это перед вызовом glVertexAttribPointer () при создании VAO.
HolyBlackCat

Ответы:

18

VAO хранит данные о расположении атрибутов вершин. (И некоторые другие данные, связанные с ними.)
"VBO bindings, active shader program, texture bindings, texture sampling/wrapping settings, uniforms"Совершенно не связаны с ним.

Вы можете спросить, почему он не помнит привязку VBO. Поскольку вам не нужно связывать VBO для рисования чего-либо, вам нужно только связать это при создании VAO: когда вы звоните glVertexAttribPointer(...), VAO вспоминает, что VBO в настоящее время связано. И VAO будет брать атрибуты из этих VBO, когда вы их рисуете, даже если эти VBO в настоящее время не связаны.


Кроме того, VAO и VBO должны использоваться по-разному:

Это не будет работать

Generate VAO
BindVAO
---- Specify vertex attributes
---- Generate VBO's
---- BindVBO's
-------- Buffer vertex data in VBO's
---- Unbind VBO's
Unbind VAO

потому что вам нужно связать VBO, чтобы указать расположение атрибутов.

Итак, вы должны сделать это так:

Generate VAO
BindVAO
Generate VBO's
BindVBO's
Specify vertex attributes

Вы можете изменить данные VBO, когда захотите, но вы должны связать их раньше.

И рисунок должен выглядеть так:

Bind VAO
Draw


Как вы могли заметить, я удалил unbindзвонки из ваших списков. Они почти полностью бесполезны и немного замедляют вашу программу, поэтому я не вижу причин для их вызова.

HolyBlackCat
источник
9
«поэтому я не вижу причин, чтобы позвонить им». чтобы предотвратить их случайное изменение. Особенно проблема при использовании сторонних библиотек.
храповик урод
Спасибо за отличный ответ! Короче говоря, VAO хранит только местоположения атрибутов вершин. VBO не восстанавливаются при привязке VAO, так как VAO знает, в каких буферах найти атрибуты. Все остальные состояния содержатся в глобальном состоянии OpenGL.
Желе ван Кампен
@JellevanCampen Да, правильно. К вашему сведению, он также хранит состояние атрибутов ( gl{Enable|Disable}VertexAttribArray()), их значения по умолчанию ( glVertexAttrib*()), режим их создания ( glVertexAttribDivisor()) и, возможно, что-то еще.
HolyBlackCat
@HolyBlackCat Вы уверены, что состояние по умолчанию (glVertexAttrib ()) является частью состояния VAO? Вики OpenGL утверждает обратное, говоря, что они являются контекстным состоянием.
RDB
@ndb Нет, я не уверен. Я ожидал, что они будут частью государства ВАО, и я не проверял это.
HolyBlackCat
4

Он хранит только привязку вершин и привязку индексного буфера

Это все параметры glVertexAttribPointerплюс буфер, связанный с Vertex_Array_buffer во время вызова glVertexAttribPointerи связанный Element_Array_buffer.

Униформа является частью текущей программы.

Все остальное - глобальное состояние.

В случае сомнений вы можете проверить таблицы состояний в спецификации используемой версии.

чокнутый урод
источник
Спасибо за ответ! Это проясняет ситуацию для меня.
Желе ван Кампен
4

Вот простое, но эффективное объяснение, в основном объект буфера имеет информацию, которую можно интерпретировать как просто биты необработанных данных, которые сами по себе ничего не значат, так что это ТОЧНО данные, которые действительно могут быть просмотрены любым способом

i.e float vbo[]={1.0,2.0,34.0...}

и способ, которым OpenGL был разработан для работы, заключается в том, что вы должны ОПРЕДЕЛИТЬ, как будут выглядеть данные, передаваемые вами в различные шейдеры.

в том, что вы также должны определить, как они будут читать эти данные, в каком формате, и что делать с ними, как они будут использоваться и для чего, вся эта информация хранится в VAO

например, вы можете объявить данные, которые хранятся в массиве, как это float vbo = {11.0,2.0,3.0,4.0}

то, что требуется затем на этом этапе, - это как интерпретировать эти данные из VBO в VAO, и что это означает следующим образом

VAO может быть установлен, чтобы читать 2 числа с плавающей точкой на вершину (что сделало бы это 2 векторами с двумя измерениями x, y), или вы можете сказать vao интерпретировать это как 1 вектор с 4 измерениями, то есть x, y, z, w и т. д.

но также другие атрибуты этих данных определяются и хранятся в VAO, такие как формат данных (несмотря на то, что вы объявили массив с плавающей точкой, вы можете указать шейдеру, что он будет считываться как целое число, и, конечно, система преобразует необработанные данные в процесс от числа с плавающей точкой до целого числа и имеет свой собственный набор правил, что делать в таких условиях)

Таким образом, в основном VBO - это данные, а VAO хранит, как интерпретировать эти данные, потому что шейдеры и сервер OpenGL спроектированы так, чтобы быть очень любопытными и должны знать все, прежде чем решат, как их обрабатывать, что с ними делать и где. поставить это

конечно, он не очень любопытный, он действительно выглядит наиболее эффективным, потому что ему нужно хранить эти данные в памяти графического сервера, чтобы он получал наиболее эффективную и быструю обработку (если он не решит, что ему не нужно делать это, если данные не должны обрабатываться таким образом и использоваться для некоторой другой информации, к которой часто не обращаются), и, следовательно, почему детали того, что делать с данными и как обрабатывать их, должны храниться в VAO, поэтому VAO похож на заголовок, а VBO - на чистые необработанные данные, которые заголовок использует и определяет (в этом случае передает атрибуты вершины шейдера), за исключением того, что VBO не ограничивается использованием только одной VAO. могут быть использованы и использованы повторно и связаны со многими VAO, например:

то, что вы можете сделать, это то, что вы можете привязать один буферный объект к VAO1, а также (отдельно) привязать один и тот же буферный объект к VAO2, причем каждый интерпретирует его по-разному, так что если ваш шейдер должен обрабатывать данные, в зависимости от того, какой VAO является тем, который является При связывании он будет обрабатывать одни и те же необработанные данные по-разному для мошенника (рисование пикселей в окне), что приведет к различному отображению одних и тех же данных, что будет зависеть от того, как вы определили их использование в VAO

hopjopper
источник
Это лучший ответ!
CodingMadeEasy