Хорошо, шаг за шагом:
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
Это связывает и генерирует объект массива вершин (VAO). Теперь ВАО не содержит никаких данных. Он просто содержит все состояния, связанные с массивами / атрибутами вершин, такими как включенные атрибуты или настройки, сделанные с помощью glVertexAttribPointer
.
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData), gCubeVertexData, GL_STATIC_DRAW);
Теперь это создает и связывает объект буфера вершин (VBO), который по существу представляет собой простой буфер данных, управляемый OpenGL, и копирует в него данные вершин.
Давайте посмотрим на эти данные:
GLfloat gCubeVertexData[216] =
{
// Data layout for each line below is:
// positionX, positionY, positionZ, normalX, normalY, normalZ,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
Ваши данные представлены в виде набора чисел с плавающей запятой (32-разрядного / 4-байтового каждого), причем каждые шесть значений представляют вершину, которая, в свою очередь, состоит из позиции (3 числа с плавающей запятой) и нормального значения (3 числа с плавающей запятой) .
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
Здесь указывается первый атрибут (позиция), который содержит 3 значения с плавающей запятой для каждой вершины с шагом 24 байта между каждой вершиной. Это означает, что это 24 байта от начала значений атрибута (в данном случае позиции) одной вершины до начала данных атрибута следующей вершины. И действительно, 24 байта - это размер 6 чисел с плавающей запятой и, следовательно, данных одной вершины в наших данных вершин, так что это точно соответствует. Последний параметр говорит, что данные о местоположении начинаются с начала текущего связанного VBO (который содержит наши данные вершин), так как это первый атрибут в наших данных вершин.
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
Указывает второй атрибут (нормальный), который должен содержать 3 значения с плавающей точкой на вершину, опять же с шагом 24 байта, как это было получено из тех же данных. Таким образом, от одного нормального до следующего это также 24 байта (6 операций с плавающей запятой). Теперь последний параметр говорит, что нормальные данные начинаются через 12 байтов (3 числа с плавающей запятой) после начала текущего связанного VBO (которое содержит наши данные вершин). Это необходимо, потому что нормаль является вторым атрибутом в наших данных вершин, поэтому нам нужно «перепрыгнуть» первые три значения (которые являются позицией), чтобы добраться до нормальных данных. Если бы мы снова использовали 0, мы бы взяли те же данные, что и для позиций.
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribNormal);
Наконец, включаются атрибуты рендеринга.
glBindVertexArrayOES(0);
Так что теперь это привязывает VAO по умолчанию (нет), так как мы закончили с его определением. Я предполагаю, что весь этот фрагмент кода является частью некоторой процедуры инициализации. Поэтому теперь всякий раз, когда мы хотим рендерить наши данные вершин, возможно, используя glDrawArrays
, нам нужно только связать VAO, используя glBindVertexArray
, перед вызовом метода рисования, и каждое состояние массива вершин, сделанное с помощью glEnableVertexAttribArray
или glVertexAttribPointer
, получает значения устанавливаются, когда VAO был привязан последним, как в нашей процедуре инициализации. Если вы не будете использовать VAO, вам придется вызывать glBindBuffer
и два вызова glEnableVetrexAttribArray
и glVertexAttribPointer
каждый раз, когда вы хотите нарисовать эти данные вершины.
Но все эти объяснения предполагают, что вы более или менее знакомы с этими понятиями. Если все эти слова ничего вам не говорят, вы должны начать с изучения какого-то реального учебного ресурса, прежде чем пытаться расшифровать код других людей.