Какова роль glBindVertexArrays против glBindBuffer и каковы их отношения?


Я новичок в OpenGL и графическом программировании. Я читал учебник, который был очень тщательно и хорошо написаны.Тем не менее, я попал в точку в коде, который я не совсем понимаю, и я хотел бы понять эти строки, прежде чем двигаться дальше.

GLuint abuffer;

glGenVertexArrays(1, &abuffer);
glBindVertexArray(abuffer);

GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

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

в книге объясняется, что 4-я-7-я строки создают буфер объекта для хранения наших данных, с 5-й строкой, дающей нам неиспользуемый идентификатор (аналогично строке 2 для объекта массива вершин?), 6-я строка, создающая буфер, и 7-я строка, выделяющая достаточную память на CPU и создающая указатель на наши данные (точки) для GL_STATIC_DRAW.

что значит для объекта быть активным? Когда бы вы впоследствии использовали abuffer? Что значит для массива вершин связывать связанные данные, и когда данные были связаны с этим объектом vertex-array?

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

любая помощь будет оценили. Спасибо.

5 60

5 ответов:

С точки зрения низкого уровня вы можете думать о массиве как о двух частях:

  • информация о размере, форме и типе массива (например, 32-разрядные числа с плавающей запятой, содержащие строки векторов с четырьмя элементами каждый).

  • массив данных, который немного больше, чем большой большой двоичный объект байтов.

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

OpenGL 3.0 / ARB_vertex_array_object

вот так наверное должны делать вещи сегодня. Очень редко можно найти людей, которые не могут использовать OpenGL 3.x и все же еще есть деньги, чтобы потратить на ваше программное обеспечение.

объект буфера в OpenGL-это большой двоичный объект битов. Подумайте о" активном " буфере как о глобальной переменной, и есть куча функций, которые используют активный буфер вместо использования параметра. Эти глобальные переменные состояния являются уродливой стороной OpenGL (до прямой государственный доступ, который рассматривается ниже).

GLuint buffer;

// Generate a name for a new buffer.
// e.g. buffer = 2
glGenBuffers(1, &buffer);

// Make the new buffer active, creating it if necessary.
// Kind of like:
// if (opengl->buffers[buffer] == null)
//     opengl->buffers[buffer] = new Buffer()
// opengl->current_array_buffer = opengl->buffers[buffer]
glBindBuffer(GL_ARRAY_BUFFER, buffer);

// Upload a bunch of data into the active array buffer
// Kind of like:
// opengl->current_array_buffer->data = new byte[sizeof(points)]
// memcpy(opengl->current_array_buffer->data, points, sizeof(points))
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

теперь ваш типичный вершинный шейдер принимает вершин как входной сигнал, не большой шарик битов. Поэтому вам нужно указать, как blob бит (буфер) декодируется в вершины. Это работа массива. Кроме того, существует" активный " массив, который вы можете считать просто глобальным переменная:

GLuint array;
// Generate a name for a new array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Make the buffer the active array buffer.
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Attach the active buffer to the active array,
// as an array of vectors with 4 floats each.
// Kind of like:
// opengl->current_vertex_array->attributes[attr] = {
//     type = GL_FLOAT,
//     size = 4,
//     data = opengl->current_array_buffer
// }
glVertexAttribPointer(attr, 4, GL_FLOAT, GL_FALSE, 0, 0);
// Enable the vertex attribute
glEnableVertexAttribArray(attr);

OpenGL 2.0 (по-старому)

В OpenGL 2.x, не было массивов вершин, и данные были просто глобальными. Ты все равно должен был позвонить glVertexAttribPointer() и glEnableVertexAttribArray(), но вы должны называть их каждый раз что вы использовали буфер. В OpenGL 3.x, вы просто настроили массив один раз.

возвращаясь к OpenGL 1.5, вы могли бы использовать буферы, но вы использовали отдельную функцию для привязки каждого вида данных. Например, glVertexPointer() для данные вершин, и glNormalPointer() для обычных данных. До OpenGL 1.5 не было буферов, но вы могли использовать указатели в памяти приложения.

OpenGL 4.3 / ARB_vertex_attrib_binding

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

GLuint array;
// Generate a name for a new array array.
glGenVertexArrays(1, &array);
// Make the new array active, creating it if necessary.
glBindVertexArray(array);

// Enable my attributes
glEnableVertexAttribArray(loc_attrib);
glEnableVertexAttribArray(normal_attrib);
glEnableVertexAttribArray(texcoord_attrib);
// Set up the formats for my attributes
glVertexAttribFormat(loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribFormat(normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexAttribFormat(texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexAttribBinding(loc_attrib,      0);
glVertexAttribBinding(normal_attrib,   0);
glVertexAttribBinding(texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
// This replaces several calls to glVertexAttribPointer()
// Note: you don't need to bind the buffer first!  Nice!
glBindVertexBuffer(0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glBindVertexBuffer(0, buffer2, 0, 32);

OpenGL 4.5 / ARB_direct_state_access

в OpenGL 4.5, или если у вас есть расширение ARB_direct_state_access, вам больше не нужно вызывать glBindBuffer() или glBindVertexArray() просто, чтобы установить вещи... массивы и буферы задаются непосредственно. Вам нужно только привязать массив в конце, чтобы нарисовать его.

GLuint array;
// Generate a name for the array and create it.
// Note that glGenVertexArrays() won't work here.
glCreateVertexArrays(1, &array);
// Instead of binding it, we pass it to the functions below.

// Enable my attributes
glEnableVertexArrayAttrib(array, loc_attrib);
glEnableVertexArrayAttrib(array, normal_attrib);
glEnableVertexArrayAttrib(array, texcoord_attrib);
// Set up the formats for my attributes
glVertexArrayAttribFormat(array, loc_attrib,      3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(array, normal_attrib,   3, GL_FLOAT, GL_FALSE, 12);
glVertexArrayAttribFormat(array, texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
// Make my attributes all use binding 0
glVertexArrayAttribBinding(array, loc_attrib,      0);
glVertexArrayAttribBinding(array, normal_attrib,   0);
glVertexArrayAttribBinding(array, texcoord_attrib, 0);

// Quickly bind all attributes to use "buffer"
glVertexArrayVertexBuffer(array, 0, buffer, 0, 32);

// Quickly bind all attributes to use "buffer2"
glVertexArrayVertexBuffer(array, 0, buffer2, 0, 32);

// You still have to bind the array to draw.
glBindVertexArray(array);
glDrawArrays(...);

ARB_direct_state_access хорош по многим причинам. Вы можете забыть о привязке массивов и буферов (за исключением случаев, когда вы рисуете), поэтому вам не нужно думать о скрытых глобальных переменных это OpenGL отслеживает для вас. Вы можете забыть о разнице между "генерацией имени для объекта" и "созданием объекта", потому что glCreateBuffer() и glCreateArray() сделайте и то и другое одновременно.

Вулкан

Вулкан идет еще дальше, и вы пишете код, подобный псевдокоду, который я написал выше. Так что вы увидите что-то вроде:

// This defines part of a "vertex array", sort of
VkVertexInputAttributeDescription attrib[3];
attrib[0].location = 0; // Feed data into shader input #0
attrib[0].binding = 0;  // Get data from buffer bound to slot #0
attrib[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attrib[0].offset = 0;
// repeat for attrib[1], attrib[2]

ваша интерпретация книги не совсем корректно. Объекты массива вершин не хранят никаких данных. Они представляют собой класс объектов, известных как контейнеры, например объекты Framebuffer. Вы можете присоединять / связывать с ними другие объекты, но сами они никогда не хранят данные. Как таковые они не являются контекстно-разделяемым ресурсом.

в основном объекты массива вершин инкапсулируют состояние массива вершин в OpenGL 3.0. Начиная с OpenGL 3.1 (вместо GL_ARB_compatibility) и профили ядра OpenGL 3.2+, вы должен иметь ненулевую ВАО-привязку во все времена для таких команд, как glVertexAttribPointer (...) или glDrawArrays (...) функции. Связанный VAO формирует необходимый контекст для этих команд и сохраняет состояние постоянно.

в более старых версиях GL (и совместимости) состояние, сохраненное VAOs, было частью глобальной машины состояний.

также стоит отметить, что" текущая " привязка для GL_ARRAY_BUFFER - это не одно из состояний, которые отслеживает VAOs. Пока это привязка используется такими командами, как glVertexAttribPointer (...), VAOs не хранят привязку они хранят только указатели (GL_ARB_vertex_attrib_binding расширение, введенное вместе с GL 4.3, немного усложняет это, поэтому давайте проигнорируем его для простоты).

VAOs do помните, что связано с GL_ELEMENT_ARRAY_BUFFER, однако, так, что индексированные команды рисования, такие как

связь создается при вызове glVertexAttribPointer.

Overview of VertexArrays

GL_VERTEX_ARRAY_BINDING и GL_ARRAY_BUFFER_BINDING константы, но они могут указывать на глобальное состояние привязки. Я имею в виду состояние не константа(оранжевый) в изображении. Используйте glGet чтобы узнать о различных глобальных состояниях.

VertexArray группирует информацию (включая буфер массива) о вершине или многих параллельных вершинах.

использовать GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING С glGetVertexAttrib чтобы найти, какой буфер массива атрибутов установлен.

glBindBuffer (GL_ARRAY_BUFFER устанавливает глобальное состояние GL_ARRAY_BUFFER_BINDING

glBindVertexArray устанавливает глобальное состояние GL_VERTEX_ARRAY_BINDING

OpenGL-это интерфейс с отслеживанием состояния. Это плохо, устарело и уродливо, но это наследие для вас.

объект массива вершин представляет собой набор буферных Привязок, которые драйвер может использовать для получения данных для вызовов draw, большинство учебников используют только один и никогда не объясняют, как использовать несколько VAOs.

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

нет никакой связи между VertexArray и VBO.

массив вершин выделяет память в ОЗУ и отправляет указатель на API. VBO выделяет память в графической карте-системная память не имеет адреса для нее. Если вам нужно получить доступ к данным vbo из системы, вам нужно сначала скопировать его из vbo в систему.

кроме того, в более новых версиях OpenGL массивы вершин полностью удаляются (depcrecated в 3.0, removed в 3.1)