Когда это связано с ВАО?

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

В частности, это некоторые из моих проблем. Если я создаю VAO:

GLuint vao;
glGenVertexArrays(1, &vao);

может ли что-нибудь связать его, прежде чем я свяжу VAO? (если я создаю VBO сейчас, он связан с VAO?)

glBindVertexArray(vao);

После привязки VAO, если я создаю VBO:

GLuint vbo;
glGenBuffers(1, &vbo);

связано ли это с VAO? Или это происходит, когда я связываю его?

glBindVertexArray(vbo);

Или, может быть, когда я что-то копирую?

Если я получаю местоположение атрибута:

att = glGetAttribLocation(program_id, "name");

связано ли это с VAO? Или это происходит после его включения:

glEnableVertexAttribArray(att);

... или после его установки:

glVertexAttribPointer(att, ...);

?

Я думаю, что EBO ведут себя точно так же, как VBOs, поэтому я надеюсь, что применяются те же "правила".

Униформы должны вести себя как глобальные, поэтому они не должны подвергаться воздействию VAO вообще.

Теперь о развязывании:

Если я "свяжу" VBO с VAO, а затем отвяжу VBO, он отсоединяется от VAO?

Если у меня есть VBO, связанный с несколькими VAO, что происходит, когда я отвязываю VBO?

И об освобождении ресурсов:

Что происходит, когда я удаляю VBO? Удаляется ли из всех ВАО? Или у них все еще есть "болтающиеся ссылки" на этот VBO?

А о программах:

IIUC Я могу повторно использовать VBOs между программами. Однако, если VAO связывают атрибуты и VBOs, а атрибуты принимают программный параметр, могу ли я повторно использовать VAO между программами? Почему атрибуты принимают параметр программы вообще?

А насчет отладки:

Есть ли способ распечатать конечный автомат OpenGL? Мне хотелось бы узнать, какие программы были связаны между собой, с какими шейдерами, в которых существуют VAO, какие VBOs привязаны к каким VAO, какие атрибуты связаны с VAO и VBOs, были ли они установлены? разрешены ли они? какие формы существуют...

И о вызовах вызова:

Предположим, кто-то дает мне VAO, и я должен его нарисовать. Есть ли способ узнать, следует ли мне звонить glDrawArrays или glDrawElements? Могу ли я как-то запросить эту информацию из ВАО? Может быть, наряду с размерами моих VBOs, хранящихся там?

Ответ 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, ...).

Ответ 2

таблицу VAO можно найти в разделе State Tables спецификации

в коде psuedo это выглядит так:

struct VAO{
    GL_INT element_array_binding; //IBO used for glDrawElements and friends
    char* label;//for debugging

    struct{//per attribute values
        bool enabled; //whether to use a VBO for it

        //corresponding to the values passed into glVertexAttribPointer call
        int size;
        unsigned int stride; 
        GL_ENUM type; 
        bool normalized;
        bool integer; //unconverted integers
        bool long; //double precision
        void* offset;
        int bufferBinding;//GL_ARRAY_BUFFER bound at time of glVertexAttribPointer call

        int attributeDiviser; //as used for instancing 

    } attributes[MAX_VERTEX_ATTRIBS];
};

Заметно отсутствует состояние программы (какая из них связана, равномерные значения и т.д.)