Рисование нескольких моделей с использованием нескольких openGL VBO

вместо того, чтобы публиковать много кода, я буду интуитивно формулировать этот вопрос. Надеюсь, вы понимаете, к чему я иду.

Я делаю игру, и в коде у меня есть модельный класс, который загружает модель и устанавливает для нее VBO.

В функции загрузки он генерирует новый идентификатор VBO и загружает данные вершин из файла в этот буфер, привязывая его и т.д. (это отлично работает)

В начале программы я делаю один объект модели и загружаю файл .obj.

В функции рендеринга я просто вызываю функцию DrawArrays() (с необходимым дополнительным материалом), и, как я уже сказал, все отлично работает, поскольку модель появляется на экране без проблем.

Однако проблема заключается в том, когда я делаю два объекта модели в начале программы и загружаю другой .obj файл в каждый из них.

Проблема в том, что когда я играю, на экране рисуется только вторая модель.

Проблема заключается в том, что я не понимаю, как работает VBO.

Вот как я "думаю" о работе VBO.

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

Теперь я знаю, что это неправильно, потому что в моем ограниченном понимании я не вижу, как я могу включить/выключить модели. Но независимо от того, сколько учебников я смотрю, я не могу ответить на этот вопрос, потому что все они сосредоточены на отображении этого ОДНОГО ПЕРВОГО VBO, что, кстати, я могу сделать.

Итак... если бы это имело смысл, может кто-нибудь просветить меня?

Ответ 1

Вы делаете это в основном правильно, но команда рисования не рисует каждый созданный вами буфер. Если вы хотите нарисовать 2 объекта с данными в разных буферах, вам придется выпустить 2 команды рисования.

Позвольте мне объяснить, основываясь на том, как я это делаю:

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

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

Вы не можете использовать сразу несколько VBO для одного и того же атрибута - вызов связать другой буфер просто перезаписывает предыдущий вызов и делает второй буфер активным, и, как я полагаю, именно поэтому вызывается только ваш второй объект.

Вы также можете использовать VAO для упрощения чертежа - в основном вы назначаете id для команд привязки, тогда вы можете выполнить их с одной строкой (подумайте о списках отображения).

Итак, моя загрузка (одного объекта) выглядит так:

  • Создание буферов (допустим, буфер 1 предназначен для данных вершин, буфер 2 для данных индекса).
  • Bind buffer 1 как буфер массива.
  • Заполнить буфер данными вершин.
  • Повторите 2 и 3 для буфера 2 как буфер массива элементов и данные индекса соответственно.

И мой рисунок (опять же, одного объекта):

  • Bind buffer 1 как буфер массива.
  • Используйте glVertexAttribPointer, чтобы указать, что этот буфер переходит к определенному атрибуту.
  • Bind buffer 2 как буфер массива элементов.
  • Вызов DrawElements

Для второго объекта вам нужно повторить все.

Ответ 2

Выполните следующие действия для рендеринга своих моделей, считая, что вершины модели1 хранятся в вершинах вершины и буфера 2 в vertexBuffer2:

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);        
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, <no. of vert>);

glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer2);
glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, <no. of vert>);

//swap buffers depending on your windowing toolkit

Обязательно не выполняйте glClear в середине двух моделей. Все самое лучшее!

Ответ 3

то, что вы хотите сделать, - установить вербальный атрибут вершин в первые данные объекта перед каждым вызовом drawArrays

функция draw arrays использует привязки, хранящиеся в VAO, чтобы найти данные, необходимые для визуализации всего

чтобы отобразить 2 модели, которые вы создаете, второе VAO связывает ее и вызывает по требованию glVertexAttribPointer. для рисования вы связываете VAO и вызываете drawArrays для каждой модели