Некоторая терминология немного неверна:
- 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 с помощью glBindVertexArray
then call, glDrawArrays
или glDrawElements
вы будете рисовать то же самое, как если бы вы делали все эти вызовы методов. Возможно, вы захотите потом отвязать VAO.
После того, как вы отвяжете VAO, все состояние вернется к тому, как было до привязки VAO. Я не уверен, сохраняются ли какие-либо изменения, которые вы вносите во время привязки VAO, но это можно легко выяснить с помощью тестовой программы. Думаю, это можно представить glBindVertexArray(0);
как привязку к "дефолтному" VAO ...
Обновление: кто-то обратил мое внимание на необходимость фактического вызова отрисовки. Как оказалось, вам действительно не нужно выполнять ПОЛНЫЙ вызов отрисовки при настройке VAO, просто все привязки. Не знаю, почему раньше считал это необходимым, но теперь это исправлено.