Некоторая терминология немного неверна:
- A
Vertex Array- это просто массив (обычно a float[]), содержащий данные вершин. Его не нужно ни к чему привязывать. Не путать с a Vertex Array Objectили VAO, о которых я расскажу позже.
- A
Buffer Object, обычно называемый a Vertex Buffer Objectпри хранении вершин или сокращенно VBO, - это то, что вы называете просто Buffer.
- Ничего не сохраняется обратно в массив вершин,
glVertexAttribPointerработает точно так же, как glVertexPointerи glTexCoordPointerработает, просто вместо именованных атрибутов вы можете указать число, определяющее ваш собственный атрибут. Вы передаете это значение как index. Все ваши glVertexAttribPointerзвонки будут поставлены в очередь, когда вы в следующий раз позвоните glDrawArraysили glDrawElements. Если у вас есть привязка VAO, VAO сохранит настройки для всех ваших атрибутов.
Основная проблема здесь в том, что вы путаете атрибуты вершин с VAO. Атрибуты вершин - это просто новый способ определения вершин, текскордов, нормалей и т. Д. Для рисования. Состояние магазина VAO. Сначала я объясню, как рисование работает с атрибутами вершин, а затем объясню, как можно сократить количество вызовов методов с помощью VAO:
- Вы должны включить атрибут, прежде чем сможете использовать его в шейдере. Например, если вы хотите отправить вершины шейдеру, вы, скорее всего, отправите его в качестве первого атрибута, 0. Поэтому перед рендерингом вам нужно включить его с помощью
glEnableVertexAttribArray(0);.
- Теперь, когда атрибут включен, вам нужно определить данные, которые он будет использовать. Для этого вам нужно привязать свой VBO -
glBindBuffer(GL_ARRAY_BUFFER, myBuffer);.
- А теперь мы можем определить атрибут -
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);. В порядке параметров: 0 - это атрибут, который вы определяете, 3 - это размер каждой вершины, GL_FLOAT- это тип, GL_FALSEозначает не нормализовать каждую вершину, последние 2 нуля означают, что на вершинах нет шага или смещения.
- Нарисуй им что-нибудь -
glDrawArrays(GL_TRIANGLES, 0, 6);
- Следующее, что вы нарисуете, может не использовать атрибут 0 (реально будет, но это пример), поэтому мы можем отключить его -
glDisableVertexAttribArray(0);
Оберните это в glUseProgram()вызовы, и у вас будет система рендеринга, которая правильно работает с шейдерами. Но предположим, что у вас есть 5 различных атрибутов, вершины, текскорд, нормали, цвет и координаты карты освещения. Прежде всего, вы должны сделать один glVertexAttribPointerвызов для каждого из этих атрибутов, и вам нужно будет заранее активировать все атрибуты. Допустим, вы определяете атрибуты 0-4, как я их перечислил. Вы можете включить их все так:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
И тогда вам придется связать различные РВО для каждого атрибута (если не хранить их все в одном VBO и использование смещениям / шаг), то вам необходимо сделать 5 различных glVertexAttribPointerвызовов, от glVertexAttribPointer(0,...);до glVertexAttribPointer(4,...);вершин , до Lightmap координат соответственно.
Надеюсь, эта система имеет смысл. Теперь я собираюсь перейти к VAO, чтобы объяснить, как их использовать, чтобы сократить количество вызовов методов при выполнении этого типа рендеринга. Обратите внимание, что использовать VAO не обязательно.
A Vertex Array Objectили VAO используются для хранения состояния всех glVertexAttribPointerвызовов и VBO, которые были нацелены при выполнении каждого из glVertexAttribPointerвызовов.
Вы создаете его с помощью вызова glGenVertexArrays. Чтобы сохранить все необходимое в VAO, свяжите его glBindVertexArray, затем выполните полный вызов отрисовки . Все вызовы привязки отрисовки перехватываются и сохраняются VAO. Вы можете отвязать VAO с помощьюglBindVertexArray(0);
Теперь, когда вы хотите нарисовать объект, вам не нужно повторно вызывать все glVertexAttribPointerпривязки VBO или вызовы, вам просто нужно связать VAO с помощью glBindVertexArraythen call, glDrawArraysили glDrawElementsвы будете рисовать то же самое, как если бы вы делали все эти вызовы методов. Возможно, вы захотите потом отвязать VAO.
После того, как вы отвяжете VAO, все состояние вернется к тому, как было до привязки VAO. Я не уверен, сохраняются ли какие-либо изменения, которые вы вносите во время привязки VAO, но это можно легко выяснить с помощью тестовой программы. Думаю, это можно представить glBindVertexArray(0);как привязку к "дефолтному" VAO ...
Обновление: кто-то обратил мое внимание на необходимость фактического вызова отрисовки. Как оказалось, вам действительно не нужно выполнять ПОЛНЫЙ вызов отрисовки при настройке VAO, просто все привязки. Не знаю, почему раньше считал это необходимым, но теперь это исправлено.