Какова роль 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 ответов:
С точки зрения низкого уровня вы можете думать о массиве как о двух частях:
информация о размере, форме и типе массива (например, 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.
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)