Что такое объекты массива вершин?

Сегодня я только начинаю изучать 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?

Кстати, приемлемо ли то руководство, которому я следую? Есть ли что-нибудь, чего мне следует остерегаться, или лучшее руководство, которому нужно следовать?


person Patrick    schedule 06.08.2012    source источник


Ответы (4)


«Объект массива вершин» предоставлен вам Подкомитетом OpenGL ARB по глупым именам.

Думайте об этом как о геометрическом объекте. (Как старый программист SGI Performer, я называю их геосетами.) Переменные / члены экземпляра объекта - это указатель вершины, обычный указатель, указатель цвета, указатель attrib N, ...

Когда VAO впервые связывается, вы назначаете эти члены, вызывая

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

и так далее. Какие атрибуты включены и указатели, которые вы указываете, хранятся в VAO.

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

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

Дополнительная информация в ответ на вопросы Патрика:

По умолчанию для вновь созданного VAO он пуст (AFAIK). Никакой геометрии, даже вершин, поэтому, если вы попытаетесь ее нарисовать, вы получите ошибку OpenGL. Это разумно, например, «инициализировать все как False / NULL / ноль».

Вам нужно только glEnableClientState, когда вы все настраиваете. VAO запоминает состояние включения / выключения для каждого указателя.

Да, VAO будет хранить glEnableVertexAttribArray и glVertexAttrib. Старые массивы вершин, нормалей, цвета, ... такие же, как массивы атрибутов, вершина == # 0 и так далее.

person Hugh    schedule 06.08.2012
comment
«Vertex Array Object предоставлен вам Подкомитетом OpenGL ARB для глупых имен». Да, такое глупое имя для объекта, в котором хранятся привязки вершин массива. - person Nicol Bolas; 06.08.2012
comment
Если я правильно вас понял, вызов glGenVertexArrays(1, &VaoId); и glBindVertexArray(VaoId); создает VAO с нормальными значениями по умолчанию, чтобы спасти вас от glEnableClientState? Или я вас совершенно не понимаю? В будущем я, скорее всего, буду использовать много glEnableClientState? - person Patrick; 06.08.2012
comment
Кроме того, связаны ли VAO с glVertexAttribPointer - person Patrick; 06.08.2012
comment
Пожалуйста, добавьте информацию об использовании общих атрибутов вершин для людей, которые используют основной профиль. - person Oskar; 06.08.2012
comment
Спасибо за дополнительную информацию. - person Patrick; 07.08.2012
comment
@NicolBolas Лучше имя VertexArrayMacro или что-то подобное. - person bobobobo; 08.07.2013
comment
Согласно вики OpenGL, glVertexAttrib является НЕ частью состояния VAO (в отличие от glVertexAttribPointer, которое есть), но вместо этого является значением состояния контекста. - person rdb; 03.07.2015
comment
+1 просто за то, что назвал это глупым именем. Атрибут массива вершин связывает то, то и другое. Геометрический объект гораздо проще представить! - person Noob Saibot; 07.07.2015
comment
Комментарии не могут содержать такой контент. +1 за geosets Комментарии не могут содержать такой контент. - person n611x007; 26.01.2017
comment
@NicolBolas Vertex Array Object - ужасное имя. Речь идет о привязке данных к атрибутам. Речь идет не о массиве вершин, как следует из названия. В имени нет ссылки на привязки или атрибуты, а поскольку массив вершин сам по себе является отдельным понятием, понимание становится еще труднее. IMHO, (Vertex) Attributes Binding Object проще для понимания. Даже Geometry Object лучше: мне он не нравится, но по крайней мере не перегружен. - person AkiRoss; 28.06.2017
comment
@AkiRoss: Речь идет не о массиве вершин, как следует из названия. Но о массивах вершин. Те буферы, которые он хранит, содержат массивы вершин. VAO описывает, как интерпретировать это хранилище как массивы данных вершин. Он описывает, какие массивы к каким атрибутам вершины переходят. И так далее. VAO - вполне законное имя. - person Nicol Bolas; 28.06.2017
comment
@NicolBolas Извините, это может быть законным, но это ужасное имя. Как видно из этого вопроса и комментариев, VAO, похоже, вызывают больше путаницы, чем любая другая фундаментальная концепция GL. Почему это могло быть? Я не думаю, что VAO сложен по своей природе, может быть, просто у него неясное имя? - person Ash; 28.09.2018
comment
@Ash: Нет, это потому, что у него ужасный API. Кто не понимает, как работают VAO? Это люди, которые используют VAO с функциями pre-DSA. Ни у кого, кто использует функции DSA (или даже glVertexAttribBinding API), нет проблем с пониманием того, как работают VAO или как их использовать. Это все вина glVertexAttribPointer, glBindBuffer(GL_ELEMENT_ARRAY_BUFFER) и им подобных. Добавьте к этому ужасные учебники, которые поощряют копирование / вставку кода без понимания его, и вот мы. - person Nicol Bolas; 28.09.2018
comment
@Hugh: если вы попытаетесь нарисовать это, вы получите ошибку OpenGL Неверно. Совершенно нормально выполнить рендеринг с пустым VAO. Атрибуты вершин будут использовать постоянные значения, но это не приведет к ошибке OpenGL. Также: Да, VAO будет хранить glEnableVertexAttribArray и glVertexAttrib. Он не хранит состояние glVertexAttrib. Он хранит данные вершин array, а glVertexAttrib состояния не являются частью массивов вершин. Это состояние контекста. - person Nicol Bolas; 25.04.2019

Я всегда думаю о VAO как о массиве буферов данных, используемых OpenGL. Используя современный OpenGL, вы создадите объекты буфера VAO и вершин.

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

//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
person vasmos    schedule 29.07.2019
comment
+1 за диаграмму. Более значимого, чем что-либо другое, что я видел. Из того, что мне удалось собрать, VAO похожа на структуру, в которой каждый член представляет собой массив равной длины. Самый важный член содержит точки в трехмерном пространстве (вершины). Другие члены содержат вспомогательные данные (атрибуты) об этих точках, такие как цвет и нормаль. Действительно раздражает, как учебники просто говорят вам копировать и вставлять код, не объясняя, что код концептуально делает. Просто копировать и вставлять можно очень мало ... - person allyourcode; 18.08.2020
comment
Оцените ответ, и диаграммы полезны, но примеры кода - нет. На самом деле они больше сбивают с толку, чем полезны. В первом примере вы вызываете glGenVertexArrays () для буферного объекта? Затем повторил glGenBuffers () с 3 аргументами? Не уверен, что это должно означать или делать, но для меня это просто не имеет смысла, не говоря уже о компиляции. - person rsp1984; 28.05.2021
comment
Фактически, я просмотрел документы Khronos и Mozilla о VAO, и ни один из них не сразу сказал, что они из себя представляют, и почему кто-то хотел бы его использовать. Старые учебники прекрасно работают без VAO ... почему? Эта страница была первой, которая дала мне представление о VAO. - person OsamaBinLogin; 20.06.2021

Объекты массива вершин похожи на макросы в программах обработки текста и т.п. Хорошее описание можно найти здесь.

Макросы просто запоминают действия, которые вы сделали, такие как активация этого атрибута, привязка этого буфера и т. Д. Когда вы вызываете glBindVertexArray( yourVAOId ), он просто воспроизводит эти привязки указателя атрибутов и привязки буфера.

Итак, ваш следующий вызов для рисования использует все, что было связано с VAO.

VAO не хранят данные вершин. Нет. Данные вершин хранятся в буфере вершин или в массиве клиентской памяти.

person bobobobo    schedule 07.07.2013
comment
-1: Они не похожи на макросы. Если бы это было так, то связывание нового VAO не отключило бы массивы вершин, включенные предыдущим VAO, если только новый VAO не записал, что вы явно отключили эти массивы. VAO, как и все объекты OpenGL, хранят состояние, а не команды. Команды просто изменяют состояние, но объекты идут с установленным состоянием по умолчанию. Вот почему привязка вновь созданного VAO будет всегда отключать все атрибуты. - person Nicol Bolas; 24.07.2013

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, чтобы лучше понять это.

person Yola    schedule 14.10.2015
comment
Приятно видеть людей, продвигающих использование OpenGL в стиле DSA. - person Nicol Bolas; 11.01.2016