Подтвердить что ты не робот

Какова роль glBindVertexArrays vs 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? Что означает, что массив вершин связывает связанные данные, и когда были связаны данные с этим объектом вершинного массива?

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

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

4b9b3361

Ответ 1

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

  • Информация о размере, форме и типе массива (например, 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() выполняют оба действия одновременно.

Vulkan

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

// 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]

Ответ 2

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

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

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

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

VAOs do помнят, что привязано к GL_ELEMENT_ARRAY_BUFFER, тем самым, чтобы индексированные команды рисования, такие как glDrawElements (...), функционировали так, как вы ожидали (например, VAO повторно используют последний буфер массива элементов).

Ответ 3

Связь создается при вызове 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

Ответ 4

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

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

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

Ответ 5

Между VertexArray и VBO нет связи.

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

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