Должны ли открепить буферы?

12

Я делаю некоторые тесты с OpenGL ES 2 и получил несколько вопросов, моя текущая программа выглядит так:

Init
-------
-> create index buffer
-> fill index buffer glBufferData 
-> create vertex buffer
-> fill vertex buffer glBufferData 

Draw
-------
 1. Apply vertex buffer

    -> Bind VAO
       -> bind vertex buffer
          - enable attributs (glVertexPointer, …)
       -> unbind vertex buffer
    -> Unbind VAO
    -> Bind VAO

 3. Apply index buffer
 4. Draw

Проблема

После некоторых исследований произошел сбой данного кода, и я понял, почему: мне нужно отменить привязку буфера индекса в части инициализации (после «заполнения буфера индекса glBufferData») или отменить привязку перед первым «Bind VAO»

Мои вопросы:

  • Могу ли я поместить свой индексный буфер в VAO (буфер фондового индекса VAO?)?
  • Нужно ли было откреплять буферы после каждого обновления (glBufferData)?

В моем приложении у меня есть несколько буферов, которые обновляются в каждом кадре (Пример: Частицы), поэтому у меня есть такой стек OpenGL:

-> bind buffer 1
-> update buffer 1
-> close buffer 1
-> bind buffer 1
-> draw

Первые 3 строки обновляют буфер Vertex, два последних объекта рисования, которые должны быть примерно такими:

-> bind buffer 1
-> update buffer 1
-> draw

Благодарность

user30088
источник

Ответы:

12

Вы, кажется, делаете много на ненужном связывании / снятии привязки. Если вы используете VAO, то вам следует связывать VAO только при настройке и при рисовании геометрии. Вы связываете VBO / IBO только тогда, когда вам нужно обновить их.

После рисования или обновления буфера вам не обязательно снимать привязку, хотя это может быть хорошей идеей, чтобы избежать случайных записей в буферы, которые были оставлены привязанными.

Теперь, взяв вашу первую последовательность операций, я ожидаю увидеть общий порядок:

На init:

  1. Создать и связать VAO. Любые VBO и IBO, которые вы связываете в последовательности, будут связаны с текущим VAO (этот).

  2. Создать и привязать индексный буфер.

    • Заполните индексный буфер с glBufferData/glMapBuffer.
  3. Создать и связать буфер вершин.

    • Заполните буфер вершин glBufferData/glMapBuffer.
  4. Установите атрибуты вершин с помощью glEnableVertexAttribArray/glVertexAttribPointerи т. Д.

  5. По желанию отсоедините все, чтобы избежать случайной модификации буферов и VAO. Не забудьте сначала отсоединить VAO . Например:glBindVertexArray(0);

На розыгрыше:

  1. Если только рисование буферов :

    • Связать ВАО;
    • Выполните вызовы розыгрыша.
  2. Если обновление и рисование :

    • Привязать VAO, VBO, IBO;
    • Обновите буферы (обновление атрибутов вершины необходимо только в том случае, если формат вершины изменился);
    • Выполните вызовы розыгрыша.
  3. При желании отсоедините, чтобы избежать случайной модификации буферов и VAO.

Это так просто. Этот порядок операций должен функционировать без проблем.

glampert
источник
2
Я хотел бы добавить, что в своих экспериментах (2014) с реальными случаями (но с простыми шейдерами, чтобы не создавать узких мест в GPU), я обнаружил, что улучшения производительности при использовании VAO были незначительными (<2% экономия ЦП) после правильного упорядочения вызовов рендеринга был реализован, чтобы полностью пропустить настройку VBO при использовании одного и того же VBO при последовательных вызовах рендеринга (от 10 до 33% экономии ресурсов ЦП), и я столкнулся с ошибками некоторых драйверов в VAO, поэтому в итоге я отключил их по умолчанию. Это было еще менее важно, когда использовались сложные шейдеры, MSAA и т. Д., Узкое место в GPU заставляло процессор в любом случае бездействовать, даже в мобильном режиме.
Стефан Хоккенхалл
2
Обратите внимание, что неправильное выравнивание данных вершин способом, который не поддерживается аппаратным обеспечением, заставит драйверы графического процессора переупорядочивать данные VBO при каждой настройке, в то время как драйверы могут переупорядочивать их один раз с VAO, если ничего не изменилось, поэтому YMMV. Лучше всего выровнять и дополнить данные вершин в любом случае.
Стефан Хоккенхалл
1
Почему VAO должен быть разложен раньше всего?
Даниэль Сафари
@DanielSafari, вы имеете в виду после установки? Если вы сначала отсоедините буфер (буфер связывания 0 / ноль), он очистит эту точку привязки в текущем VAO. Вот почему нулевой VAO должен быть установлен первым.
Гламперт
@glampert - нет, это не то, как работают привязки; привязка буфера используется, когда вызывается glVertexAttribPointer, а не иначе (исключение: GL_ELEMENT_ARRAY_BUFFER). Изменение привязки буфера после вашего вызова glVertexAttribPointer не имеет никакого эффекта.
Максимус