2012-01-14 3 views
7

Я пришел от этого вопроса:Структура OpenGL VAO/VBO для модели с движущимися частями?

opengl vbo advice

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

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

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

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

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

ответ

13

first, off VAO только «запоминает» последние привязки атрибутов вершин (и привязку VBO для буфера индекса (GL_ELEMENT_ARRAY_BUFFER_BINDING), если таковой имеется). Поэтому он не помнит смещения в glDrawElements(), вам нужно позвонить позже, используя VAO. Это 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 и VBOs для разных частей сетки (так что рисовать отдельные части легко), или вы можете объединить все в одну пару VAO VBO (так что вам нужно не звоните glBind*()) и используйте несколько звонков glDraw*(), чтобы нарисовать отдельные части сетки (как видно из кода выше - представьте себе первый glDrawElements() рисует корабль, а второй рисует башню, вы просто обновляете некоторую матричную форму между вызовами).

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

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

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

+0

Круто я думаю я получаю это с чередованием, должен попробовать. Но я думаю, что вы допустили ошибку, чтобы быть уверенным в том, что в первую очередь glVertexAttribPointer для вершинных позиций, поскольку я понял, что вершинные позиции плотно упакованы в vbo [0], но вы дали ему шаг? Если шаг не равен нулю для позиций, поскольку они не чередуются. – CodeMonkey

+0

Мне нравится идея о ID сетки в шейдере и передать ее как атрибут, но как бы я начал разбирать во многих матрицах в шейдер (как единообразный массив)? Является ли это тем, что я могу использовать UBO для передачи, скажем, 10 различных матриц преобразования для 10 различных башенок и использовать индекс, проанализированный как атрибут, для поиска правильной матрицы внутри шейдера? Это также позволило бы мне использовать функции glMultiDrawElements/Arrays, рисующие целый корабль с несколькими частями за один раз? – CodeMonkey

+0

Привет, хорошее наблюдение с шагом. Но это не ошибка. Либо я мог бы оставить шаг 0, и OpenGL знал бы (со второго и третьего аргументов), что у меня есть поток 3D GL_FLOATS (и, следовательно, размер 3 * sizeof (float)), или я могу рассчитать шаг для него. В этом нет ничего плохого. Для дальнейшего уточнения - шаг - расстояние между адресами двух последовательных вершин, это НЕ пространство между ними (поэтому 0 не означает, что между вершинами нет неиспользуемых байтов, это означает, что OpenGL должен вычислять реальный шаг из числа измерений и используемый тип данных). –

0

@theswine

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

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

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

+0

Привет. Я просто видел это случайно, так как пользователи не получают уведомление, когда вы отправляете ответ, начиная с '@ login' (только OP уведомляется об этом). Вы должны были оставить комментарий в моем ответе, я был бы уведомлен об этом. Я предлагаю вам начать новый вопрос и опубликовать минимальный код, который воспроизводит ваш сбой. Это возможно? Затем вы можете оставить комментарий «@ login» ниже этого комментария, и я рассмотрю вашу проблему. –

+0

Извините, я не смог комментировать ваш пост из-за моей нехватки репутации. Но плохо попытайтесь что-то бросить для вас, чтобы проверить (возможно, это просто мое оборудование?) – luveti

+0

Обычно это просто обменный индекс или запутанная привязка. Бывает к лучшему. Иногда буфер элемента (index) создает проблемы, особенно на графических картах Intel. –

Смежные вопросы