OpenGL структура VAO / VBO для модели с движущимися частями? - PullRequest
7 голосов
/ 14 января 2012

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

opengl vbo advice

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

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

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

Каждый узел в assimp может содержать несколько сеток, где каждая сетка имеет текстуру, вершины, нормали, материал и т. Д. Узлы в assimp содержат преобразования. Скажем, у меня есть корабль с пушечной башней. Я хочу иметь возможность вращать башню. Означает ли это, что я сделаю судовой узел отдельной 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 (объекты с единым буфером), но, похоже, я могу передать несколько униформ, поможет ли это мне содержать полную модель с подвижными деталями в одной VAO?

Ответы [ 2 ]

13 голосов
/ 15 января 2012

сначала, выключено VAO только «запоминает» последние привязки атрибутов вершин (и привязку VBO для буфера индекса (GL_ELEMENT_ARRAY_BUFFER_BINDING), если он есть). Таким образом, он не запоминает смещения в glDrawElements(), вам необходимо вызвать его позже при использовании VAO. Это не мешает вам использовать чередующиеся массивы вершин. Позвольте мне попытаться объяснить:

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 и одно или несколько VBO.

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

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

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

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

0 голосов
/ 29 января 2014

@ theswine

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

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

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

...