Структура OpenGL VAO / 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
(кстати: извините за поднятие старой темы, я просто подумал, что это может быть полезно для других, этот пост наверняка был! (кстати, спасибо!!))