Структура OpenGL VAO / VBO для модели с движущимися частями?

Я пришел от этого вопроса:

opengl VBO советы

Я использую OpenGL 3.3 и не буду использовать устаревшие функции. Im использует Assimp для импорта моделей blender. Но я немного смущен тем, насколько я должен разделить их с точки зрения ВАО и VBO.

сначала небольшой побочный вопрос. Я использую glDrawElements, это означает, что я не могу чередовать свои атрибуты вершин или может vao выяснить, используя glVertexAttribPointer и glDrawElements смещение, чтобы увидеть, где моя позиция вершины?

главный вопрос, который я думаю, сводится к тому, как структурировать мои VAO/VBO для модели с несколькими движущимися частями и несколькими сетками pr. часть.

каждый узел в assimp может содержать несколько сеток, где каждая сетка имеет текстуру, вершины, нормали, материал и т. д. Узлы в assimp содержат преобразования. Скажем, у меня есть корабль с пушечной башней. Я хочу быть в состоянии roatate башни. Значит ли это, что я буду сделайте узел корабля отдельным VAO с VBO для каждой сетки, содержащей ее атрибуты(или несколько VBO и т. д.). Я думаю, это звучит как

draw(ship);    //call to draw ship VAO
pushMatrix(turretMatrix)  //updating uniform modelview matrix for the shader
draw(turret);  //call to draw turret VAO

Я еще не полностью понимаю UBO (однородные буферные объекты), но, похоже, я могу пройти в нескольких униформах, это поможет мне содержать полную модель с подвижными частями в одном ВАО?

2 ответов


во-первых, off VAO только "запоминает" последние привязки атрибутов вершин (и привязку VBO для буфера индекса (GL_ELEMENT_ARRAY_BUFFER_BINDING), если он есть). Поэтому он не помнит смещений в glDrawElements(), вам нужно вызвать это позже при использовании ВАО. Это laso не мешает вам использовать чередующиеся массивы вершин. Позвольте мне объяснить:

int vbo[3];
glGenBuffers(3, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, data0, size0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, data1, size1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, data2, size2);
// create some buffers and fill them with data

int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// create a VAO

{
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO
    glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(float), NULL); // this is VAO saved state
    glEnableVertexAttribArray(0); // this is VAO saved state
    // sets up one vertex attrib array from vbo[0] (say positions)

    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // not saved in VAO
    glVertexAttribPointer(1, 3, GL_FLOAT, false, 5 * sizeof(float), NULL); // this is VAO saved state
    glVertexAttribPointer(2, 2, GL_FLOAT, false, 5 * sizeof(float), (const void*)(2 * sizeof(float))); // this is VAO saved state
    glEnableVertexAttribArray(1); // this is VAO saved state
    glEnableVertexAttribArray(2); // this is VAO saved state
    // sets up two more VAAs from vbo[1] (say normals interleaved with texcoords)

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // this is VAO saved state
    // uses the third buffer as the source for indices
}
// set up state that VAO "remembers"

glBindVertexArray(0); // bind different vaos, etc ...

позже ...

glBindVertexArray(vao); // bind our VAO (so we have VAAs 0, 1 and 2 as well as index buffer)
glDrawElements(GL_TRIANGLE_STRIP, 57, GL_UNSIGNED_INT, NULL);
glDrawElements(GL_TRIANGLE_STRIP, 23, GL_UNSIGNED_INT, (const void*)(57 * sizeof(unsigned int)));
// draws two parts of the mesh as triangle strips

так что вы видите ... вы можете рисовать чередующиеся массивы вершин, используя glDrawElements использование одного VAO и одного или нескольких РВО.

чтобы ответить на вторую часть вашего вопроса, Вы можете иметь разные VAOs и VBOs для разных частей сетки (поэтому рисовать отдельные части легко), или вы можете сплавить все в одну пару VAO VBO (так что вам не нужно звонить glBind*() часто) и использовать несколько glDraw*() вызовы для рисования отдельных частей сетки (как показано в коде выше-представьте первый glDrawElements() рисует корабль, а второй рисует башню, вы просто обновляете некоторую матрицу между телефонные переговоры.)

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

As однородные объекты буфера идут, единственное преимущество заключается в том, что вы можете упаковать в них много данных и что их можно легко разделить между шейдерами (просто привязать UBO к любому шейдеру, который может его использовать). Нет никакого реального преимущества в их использовании для вас, за исключением того, что у вас будут объекты с 1OOOs матриц.

кроме того, я написал исходные коды выше по памяти. Дайте мне знать, если есть некоторые ошибки / проблемы ...


@theswine

не связывание этого во время инициализации VAO приводит к сбою моей программы, но связывание ее после связывания VAO заставляет ее работать правильно. Ты уверен, что это не сохранено в ВАО?

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO

(кстати: извините за поднятие старой темы, я просто подумал, что это может быть полезно для других, этот пост наверняка был! (кстати, спасибо!!))