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

Каков правильный способ изменения вершинного буфера OpenGL?

Я устанавливаю буфер вершин в OpenGL, например:

int vboVertexHandle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_DYNAMIC_DRAW);

Позже, если я хочу добавить или удалить вершины в "vertexData", каков правильный способ сделать это? Возможно ли это? Я предполагаю, что не могу просто изменить массив напрямую, не пересылая его на GPU.

Если я изменяю массив vertexData, тогда вызывайте это снова:

glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glBufferData(GL_ARRAY_BUFFER, vertexData, GL_DYNAMIC_DRAW);

... будет ли перезаписывать старый буфер моими новыми данными? Или мне также нужно удалить старый? Есть ли лучший способ?

4b9b3361

Ответ 1

Размер любого объекта буфера OpenGL устанавливается при вызове glBufferData. То есть OpenGL будет выделять объем памяти, указанный вами во втором аргументе glBufferData (который не указан в OP). Фактически, если вы вызываете, например glBufferData( GL_ARRAY_BUFFER, bufferSize, NULL, GL_DYNAMIC_DRAW );, OpenGL создаст буфер из bufferSize байтов неинициализированных данных.

Вы можете загрузить любое количество данных (вплоть до размера буфера) с помощью glBufferSubData, glMapBuffer или любой другой процедуры для передачи данных. Единственный способ изменить размер буфера - вызвать glBufferData с новым размером для того же идентификатора буфера (значение, возвращаемое с glGenBuffers).

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

Ответ 2

http://www.opengl.org/wiki/GLAPI/glBufferData

glBufferData создает новое хранилище данных для объекта-буфера, привязанного в данный момент к цели. Любое ранее существующее хранилище данных удаляется.

Это объясняет, что вызов glBufferData будет "перераспределять" данные, буфер будет иметь новый размер. Все старые данные будут потеряны. Если вы хотите записать только часть буфера, используйте glBufferSubData вместо этого.

http://www.opengl.org/wiki/GLAPI/glBufferSubData

Изменить: glBufferSubData - только если вы хотите заменить данные; вместо этого измените размер буфера, вы должны вызвать glBufferData.

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

Ответ 3

1 с использованием glMapBuffer

void mapBuffer(uint &id, void *data, uint size, uint type) {
    glBindBuffer(type, id);
    // get pointer
    void *ptr = glMapBuffer(type, GL_WRITE_ONLY);
    // now copy data into memory
    memcpy(ptr, data, size);
    // make sure to tell OpenGL we're done with the pointer
    glUnmapBuffer(type);
}

2 с помощью glBufferSubData

 void updateBuffer(uint &id, uint offset, void *data, uint size, uint type) {
        glBindBuffer(type, id);
        glBufferSubData(type, offset, size, data);
    }

Определяет размер в байтах заменяемой области хранилища данных

mapBuffer(vbo, vertex.data(), sizeof(uint)*vertex.size(), GL_ARRAY_BUFFER);
resetBuffer(vbo, vertex.data(), sizeof(uint)*vertex.size(), GL_ARRAY_BUFFER);
updateBuffer(vbo, 0, vertex.data(), sizeof(uint)*vertex.size(), GL_ARRAY_BUFFER);

если вы хотите, вы также можете использовать glBufferData → но он удаляет все старые данные и повторно использует тот же буфер glInvalidateBufferSubData → он помещает NULL во все места, и теперь вы можете кормить ваши собственные данные.