Ответ 1
Это много подзапросов. Но поскольку это область, которая часто путает новых энтузиастов OpenGL, позвольте мне попытаться предоставить некоторый контент, который, надеюсь, поможет большему количеству людей. Я намеренно просмотрю некоторые детали, такие как атрибуты вершин, которые не получены из буфера, чтобы не писать здесь книгу.
Главное, чтобы понять, что VAO представляет собой набор состояния. У него нет данных. Это VBOs, которые владеют данными вершин. С другой стороны, VAO содержит все состояние, используемое для описания того, откуда получает вызов draw от его атрибутов вершин. Это включает в себя для каждого атрибута:
- Если он включен.
- В каком буфере хранится атрибут.
- С каким смещением в буфере начинаются данные.
- Интервал между последующими атрибутами (например, шаг).
- Тип данных.
- Число компонентов.
Плюс, только один раз:
- Какой буфер массива элементов привязан.
Сопоставляя это для вызовов API, следующие вызовы меняют состояние, отслеживаемое связанным в настоящее время VAO:
-
glEnableVertexAttribArray(...)
-
glDisableVertexAttribArray(...)
-
glVertexAttribPointer(...)
-
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ...)
Обратите внимание, что это не включает текущую привязку GL_ARRAY_BUFFER
. Буфер, используемый для каждого атрибута, отслеживается косвенно, основываясь на том, какой буфер был связан, когда glVertexAttribPointer()
вызывается для конкретного атрибута.
Это должно установить основу для конкретных вопросов:
Если я создаю VAO, может ли что-нибудь связать его, прежде чем я свяжу VAO?
Нет. VAO необходимо связать, прежде чем вы сможете изменить любое состояние, сохраненное в нем.
(если я создаю VBO сейчас, связан ли он с VAO?)
Нет. Вы можете связать VBO, прежде чем связывать VAO, и заполнить VBO данными с помощью glBufferData()
. VBO - это, по сути, просто немой контейнер данных. Но любая установка атрибутов вершин, отслеживаемая в VAO, может быть выполнена только после того, как VAO привязан.
Если я получаю местоположение атрибута, он связан с VAO?
Нет, glGetAttribLocation()
выполняет только то, что предлагает название, которое получает местоположение атрибута. Он не меняет никакого состояния. Вы будете использовать расположение атрибутов для вызовов типа glEnableVertexAttribArray()
и glVertexAttribPointer()
.
Или это происходит после включения его... или после его установки
Связь атрибута с данным VBO устанавливается, когда вы вызываете glVertexAttribPointer()
, в то время как данный VBO связан.
Я думаю, что EBO ведут себя так же, как VBOs, поэтому я надеюсь, что применяются те же "правила".
В основном, но не полностью. Связывание GL_ELEMENT_ARRAY_BUFFER
- это часть состояния, хранящегося в VAO. Это имеет смысл, потому что для вызова рисования используется только один буфер массива элементов (в то время как атрибуты вершин могут поступать из нескольких разных буферов массивов), и нет отдельного вызова, который указывает "использовать данные индекса из текущего буфера массива связанных элементов", например glVertexAttribPointer()
указывает "использовать данные вершин из текущего связанного буфера массива". Вместо этого это происходит неявно, когда вы вызываете glDrawElements()
. Следовательно, буфер массива элементов должен быть привязан во время вызова рисования, и эта привязка является частью состояния VAO.
Униформы должны вести себя как глобальные, поэтому они не должны подвергаться воздействию VAO вообще.
Правильно. Униформы связаны с шейдерными программами, а не с VAO.
Если я "свяжу" VBO с VAO, а затем отвяжу VBO, он отсоединяется от VAO?
Нет. Я считаю, что это уже объяснено выше.
Если у меня есть VBO, связанный с несколькими VAO, что происходит, когда я отвязываю VBO?
Поскольку ничего не происходит с одним VAO, все еще ничего с несколькими VAO.
Что происходит, когда я удаляю VBO? Удаляется ли из всех ВАО? Или у них все еще есть "болтающиеся ссылки" на этот VBO?
Это один из более темных углов OpenGL. Если вы можете прочесть точные правила удаления для всех типов объектов (они не все одинаковые), вы достигли продвинутого уровня... В этом случае VBO автоматически отключается от привязанного в настоящее время VAO, но не из других VAO, которые в настоящее время не связаны. Если другие VAO имеют ссылки на VBO, VBO останется в живых до тех пор, пока все эти привязки не будут сломаны или удалены VAO.
Однако, если VAO связывают атрибуты и VBOs, а атрибуты принимают программный параметр, могу ли я повторно использовать VAO между программами?
Да, вы можете использовать VAO для нескольких программ. Состояние программы и состояние VAO являются независимыми. Расположение атрибута вершины в программе указывает, какой атрибут вершины используется для источника значений для каждой переменной attribute
/in
в вершинном шейдере.
Пока несколько программ используют одни и те же местоположения для одних и тех же атрибутов, вы можете использовать один и тот же VAO. Чтобы сделать это возможным, вы можете указать местоположение атрибута для каждой программы, используя директиву layout (location=...)
вершинный шейдер или вызывая glBindAttribLocation()
перед связыванием программы.
Есть ли способ распечатать конечный автомат OpenGL?
Существуют вызовы glGet*()
, которые позволяют получить почти все текущее состояние OpenGL. Не удобно, но все это доступно. Многие платформы/вендоры также предоставляют инструменты разработчика, которые позволяют просматривать состояние OpenGL в данной точке выполнения вашей программы.
Предположим, кто-то дает мне VAO, и я должен его нарисовать. Есть ли способ узнать, следует ли мне вызвать glDrawArrays или glDrawElements?
Это необычный сценарий. В большинстве случаев вы создаете VAO, чтобы вы знали, как его рисовать. Или, если кто-то другой создал его, вы попросите их нарисовать его. Но если вам это действительно нужно, вы можете получить текущий буфер массива элементов с glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, ...)
.