необходимо несколько вызовов glVertexAttribPointer? - PullRequest
1 голос
/ 23 марта 2020

, следуя главе по освещению в серии Learnopengl , автор предоставляет такой код при создании нескольких VAO s (объектов Vertex Array):

    unsigned int VBO, cubeVAO;
    glGenVertexArrays(1, &cubeVAO);
    glGenBuffers(1, &VBO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindVertexArray(cubeVAO);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); //#this
    glEnableVertexAttribArray(0);

    // second, configure the light's VAO (VBO stays the same; the vertices are the same for the light object which is also a 3D cube)
    unsigned int lightVAO;
    glGenVertexArrays(1, &lightVAO);
    glBindVertexArray(lightVAO);

    // we only need to bind to the VBO (to link it with glVertexAttribPointer), no need to fill it; the VBO's data already contains all we need (it's already bound, but we do it again for educational purposes)
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); //#this
    glEnableVertexAttribArray(0);

Здесь мы вы используете один и тот же VBO с несколькими VAO, но вызов glVertexAttribPointer выполняется дважды с одним и тем же параметром. Ранее в этом уроке он упоминает:

Каждый атрибут вершины берет свои данные из памяти, управляемой VBO, и из какого VBO он берет свои данные (у вас может быть несколько VBO): определяется VBO, в настоящее время связанным с GL_ARRAY_BUFFER при вызове glVertexAttribPointer. Поскольку ранее определенный VBO по-прежнему связан до вызова glVertexAttribPointer, атрибут вершины 0 теперь связан с его данными вершины.

итак, не означает ли это, что эти два вызова являются избыточными, или это необходимо и вызовет проблемы в будущем, если не будет сделано?

1 Ответ

3 голосов
/ 23 марта 2020

итак, не означает ли это, что эти два вызова избыточны, или это необходимо и вызовет проблемы в будущем, если не будет сделано?

Нет. Посмотрите порядок операций здесь.

// 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;
  }
};
...