需要多次调用glVertexAttribPointer吗?

问题描述 投票:0回答:1

while following the lighting chapter in the learnopengl series,作者在创建多个VAO s(顶点数组对象)时提供了这种代码:

    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的调用使用相同的参数进行了两次。他提到的Earlier in this lesson

每个顶点属性从VBO管理的内存中获取数据,而从哪个VBO获取数据(您可以有多个VBO)由当前调用glVertexAttribPointer绑定到GL_ARRAY_BUFFER的VBO确定。由于先前定义的VBO在调用glVertexAttribPointer之前仍然绑定,所以现在将顶点属性0与它的顶点数据关联。

所以,这并不意味着这两个调用是多余的,还是这是必要的,如果不执行,将会引起问题吗?

opengl vbo vao
1个回答
1
投票

所以,这并不意味着这两个调用是多余的,还是这是必要的,如果不执行,将会引起问题吗?

没有在这里查看操作顺序。

// 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将包含完全为零顶点属性的绑定。这意味着顶点着色器中的任何属性都不会接收任何数据。

在您的原始代码中,不需要第二次调用glBindBuffer。还要说真的,因为cubeVAO和lightVAO仅具有一个属性,该属性是从同一缓冲区读取的。在这里只需使用一个VAO就可以了。

\ edit

最好是根据插槽而不是实例来考虑。 GPU将支持固定数量的顶点属性(对GL_MAX_VERTEX_ATTRIBS进行glGet可以找出多少个)。因此,唯一受支持的索引将是:0->(GL_MAX_VERTEX_ATTRIBS-1),因此说“创建了新实例”并不是很准确(因为这意味着动态分配)。该行为更类似于:

// 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;
  }
};
© www.soinside.com 2019 - 2024. All rights reserved.