【问题标题】:multiple calls to glVertexAttribPointer necessary?需要多次调用 glVertexAttribPointer 吗?
【发布时间】:2020-07-03 14:25:40
【问题描述】:

while following the lighting chapter in the learnopengl series,作者在创建多个VAOs(Vertex Array Objects)时提供了这种代码:

    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】:

    那么,这是否意味着这两个调用是多余的,或者这是必要的,如果不这样做会导致问题?

    没有。看看这里的操作顺序。

    // 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。

    \编辑

    从插槽而不是实例的角度来考虑它可能会更好。您的 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;
      }
    };
    

    【讨论】:

    • 可以说每次调用glVertexAttribPointer 都会在该VAO 中创建一个AttribPointer 的新实例(从概念上讲,因为opengl 都是c)?
    • 那么glVertexAttribPointerindex 参数呢,它是否仅对VAO 唯一?
    • 最多有 GL_MAX_VERTEX_ATTRIBS 索引。 VAO 只是存储每个缓冲区的状态,以及它们绑定到哪些缓冲区(最初,它们都将被禁用)。添加了一些您可能会在 GL 驱动程序中找到的伪代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    相关资源
    最近更新 更多