уточнение glVertexAttribPointer - PullRequest
       5

уточнение glVertexAttribPointer

92 голосов
/ 02 января 2012

Просто хочу убедиться, что я правильно понимаю (я бы спросил в SO Chat, но он там мертв!):

У нас есть массив вершин, который мы делаем «текущим», связывая его
тогда у нас есть буфер, который мы связываем с целью
затем мы заполняем эту цель через glBufferData который по существу заполняет все, что было связано с этой целью, то есть наш буфер
и затем мы вызываем glVertexAttribPointer, который описывает, как данные расположены - данные, которые связаны с GL_ARRAY_BUFFER и этот дескриптор сохраняется в нашем исходном массиве вершин

(1) Правильно ли мое понимание?
Документация немного разбирается в том, как все соотносится.

(2) Есть ли какой-нибудь Vertex Array по умолчанию? Потому что я забыл / пропустил glGenVertexArrays и glBindVertexArray, и моя программа без него работала нормально.


Редактировать: Я пропустил шаг ... glEnableVertexAttribArray.

(3) Связан ли атрибут вершины с массивом вершин во время вызова glVertexAttribPointer, и тогда мы можем включить / отключить этот атрибут через glEnableVertexAttribArray в любое время, независимо от того, какой массив вершин в настоящее время связан?

Или (3b) Связан ли атрибут вершины с массивом вершин во время вызова glEnableVertexAttribArray, и, таким образом, мы можем добавить один и тот же атрибут вершины в несколько массивов вершин, вызывая glEnableVertexAttribArray в разное время, когда разные вершины Массивы связаны?

Ответы [ 2 ]

207 голосов
/ 03 января 2012

Некоторая терминология немного неправильная:

  • A Vertex Array - это просто массив (обычно float[]), содержащий данные вершин.Это не должно быть связано с чем-либо.Не путать с Vertex Array Object или VAO, о которых я расскажу позже
  • A Buffer Object, обычно называемый Vertex Buffer Object при хранении вершин, или VBO для краткости, это то, что вы 'Вызывая просто Buffer.
  • Ничего не сохраняется обратно в массив вершин, glVertexAttribPointer работает точно так же, как glVertexPointer или glTexCoordPointer работа, просто вместо именованных атрибутов вы можете указать числоэто определяет ваш собственный атрибут.Вы передаете это значение как index.Все ваши glVertexAttribPointer звонки ставятся в очередь на следующий раз, когда вы наберете glDrawArrays или glDrawElements.Если у вас есть привязка к VAO, VAO сохранит настройки для всех ваших атрибутов.

Основная проблема заключается в том, что вы путаете атрибуты вершин с VAO.Атрибуты вершин - это просто новый способ определения вершин, текстовых координат, нормалей и т. Д. Для рисования.ВАОс магазин гос.Сначала я объясню, как рисование работает с атрибутами вершин, а затем объясню, как можно сократить количество вызовов методов с помощью VAO:

  1. Вы должны включить атрибут, чтобы использовать его вшейдер.Например, если вы хотите отправить вершины в шейдер, вы, скорее всего, отправите его в качестве первого атрибута, 0. Поэтому перед рендерингом вам необходимо включить его с помощью glEnableVertexAttribArray(0);.
  2. И теперь мы можем определить атрибут - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);.В порядке параметра: 0 - это атрибут, который вы определяете, 3 - размер каждой вершины, GL_FLOAT - тип, GL_FALSE означает не нормализовать каждую вершину, последние 2 нуля означают отсутствие шага или смещения.на вершинах.
  3. Нарисуйте что-нибудь с ним - glDrawArrays(GL_TRIANGLES, 0, 6);
  4. Следующее, что вы рисуете, может не использовать атрибут 0 (реально это будет, но это пример), поэтому мы можем отключитьit - glDisableVertexAttribArray(0);

Оберните это в glUseProgram() вызовов, и у вас есть система рендеринга, которая работает с шейдерами должным образом.Но скажем, у вас есть 5 различных атрибутов, вершин, текстовых координат, нормалей, координат цвета и карты освещения.Прежде всего, вы будете делать один glVertexAttribPointer вызов для каждого из этих атрибутов, и вам придется заранее включить все атрибуты.Допустим, вы определяете атрибуты 0-4, как я их перечислил.Вы бы включили все из них следующим образом:

for (int i = 0; i < 5; i++)
    glEnableVertexAttribArray(i);

И затем вам придется связывать разные VBO для каждого атрибута (если вы не сохраните их все в одном VBO и не используете смещения / шаг), тогда вам нужносделать 5 различных вызовов glVertexAttribPointer, от glVertexAttribPointer(0,...); до glVertexAttribPointer(4,...); для вершин и координат карты освещения соответственно.

Надеемся, что эта система имеет смысл.Теперь я собираюсь перейти к VAO, чтобы объяснить, как их использовать, чтобы сократить количество вызовов методов при выполнении этого типа рендеринга.Обратите внимание, что использование VAO не обязательно.

A Vertex Array Object или VAO используется для хранения состояния всех вызовов glVertexAttribPointer и VBO, которые были нацелены, когда был сделан каждый из вызовов glVertexAttribPointer.

Вы генерируете один вызов glGenVertexArrays.Чтобы хранить все, что вам нужно, в VAO, свяжите его с glBindVertexArray, а затем выполните полный вызов ничьей Все вызовы draw bind перехватываются и сохраняются VAO.Вы можете отменить привязку VAO с помощью glBindVertexArray(0);

Теперь, когда вы хотите нарисовать объект, вам не нужно повторно вызывать все привязки VBO или glVertexAttribPointer, вам просто нужно привязатьVAO с glBindVertexArray, затем вызовите glDrawArrays или glDrawElements, и вы будете рисовать точно так же, как если бы вы делали все эти вызовы методов.Возможно, вы захотите потом отменить привязку VAO.

Как только вы открепите VAO, все состояние вернется к тому, что было до того, как вы связали VAO. Я не уверен, сохраняются ли какие-либо изменения, которые вы вносите во время привязки VAO, но это легко определить с помощью тестовой программы. Я думаю, вы можете думать о glBindVertexArray(0); как о привязке к "по умолчанию" VAO ...


Обновление: Кто-то обратил мое внимание на необходимость фактического розыгрыша. Как выясняется, при настройке VAO вам на самом деле не нужно выполнять FULL-вызов, только все связывающие вещи. Не знаю, почему я думал, что это было необходимо раньше, но сейчас это исправлено.

2 голосов
/ 01 января 2016

Терминология и последовательность вызываемых API-интерфейсов действительно довольно запутанные. Еще более запутанным является то, как различные аспекты - буфер, общий атрибут вершины и переменная атрибута шейдера - связаны. См. OpenGL-терминология для довольно хорошего объяснения.

Далее, ссылка OpenGL-VBO, шейдер, VAO показывает простой пример с необходимыми вызовами API. Это особенно хорошо для тех, кто переходит из непосредственного режима в программируемый конвейер.

Надеюсь, это поможет.

Редактировать: Как видно из комментариев ниже, люди могут делать предположения и делать поспешные выводы. Реальность такова, что это довольно запутанно для начинающих.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...