итак, не означает ли это, что эти два вызова избыточны, или это необходимо и вызовет проблемы в будущем, если не будет сделано?
Нет. Посмотрите порядок операций здесь.
// the buffer bound to GL_ARRAY_BUFFER is VBO,
// from here, until the end of the code in this block
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// start modifying the cubeVAO
// cubeVAO currently knows NOTHING about which attributes are needed.
glBindVertexArray(cubeVAO);
// set up info about vertex attribute 0, within cubeVAO.
// cubeVAO now knows about 1 attribute, index == 0
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); //#this
glEnableVertexAttribArray(0);
// now start setting up the lightVAO.
// note that at this point, VBO is still bound to GL_ARRAY_BUFFER
glBindVertexArray(lightVAO);
// set up info about vertex attribute 0, within lightVAO.
// lightVAO now knows about 1 attribute, index == 0
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
Если вы пропустите вторые вызовы glVertexAttribPointer и glEnableVertexAttribArray, lightVAO будет содержать привязки именно для атрибутов вершин ZERO. Это означает, что никакие атрибуты в вашем вершинном шейдере не получат никаких данных.
В вашем исходном коде второй вызов glBindBuffer не требуется. Также верно сказать, что поскольку cubeVAO и lightVAO имеют только один атрибут, который читается из одного и того же буфера; здесь можно было бы просто использовать один VAO.
\ edit
Вероятно, лучше думать об этом с точки зрения слотов, а не случаев. Существует фиксированное количество атрибутов вершин, которые будут поддерживаться вашим графическим процессором (сделайте glGet для GL_MAX_VERTEX_ATTRIBS, чтобы узнать, сколько). Таким образом, единственными поддерживаемыми индексами будут: 0 -> (GL_MAX_VERTEX_ATTRIBS-1), поэтому не совсем точно сказать, что «создан новый экземпляр» (поскольку это подразумевает динамическое распределение c). Поведение более сродни:
// struct to store info about a vertex attribute
struct VertexAttribute
{
bool enabled = false; //< on or off?
int size;
GLenum dataType;
bool normalise;
int stride;
size_t offset;
GLuint buffer; //< which buffer was bound to GL_ARRAY_BUFFER
};
// the VAO just stores the current state of the vertex bindings
struct VAO
{
VertexAttribute vertexAttribs[GL_MAX_VERTEX_ATTRIBS];
void glVertexAttribPointer(
int index, int size, GLenum type,
bool normalise, int stride, size_t offset)
{
vertexAttribs[index].size = size;
vertexAttribs[index].dataType = type;
vertexAttribs[index].normalise = normalise;
vertexAttribs[index].stride = stride;
vertexAttribs[index].offset = offset;
// grab buffer
vertexAttribs[index].buffer = glGet(GL_ARRAY_BUFFER_BINDING);
}
void glDisableVertexAttribArray(uint32_t index)
{
vertexAttribs[index].enabled = false;
}
void glEnableVertexAttribArray(uint32_t index)
{
vertexAttribs[index].enabled = true;
}
};