VBO必须在VAO之后绑定

Posted

技术标签:

【中文标题】VBO必须在VAO之后绑定【英文标题】:VBO must be bound after VAO 【发布时间】:2018-09-09 13:53:09 【问题描述】:

代码:

void render()

    glClear(GL_COLOR_BUFFER_BIT);

    GLfloat vertices[6][4] = 
         1.0f, 1.0f, 1.0f, 1.0f ,
         1.0f, 1.0f, 1.0f, 1.0f ,
         1.0f, 1.0f, 1.0f, 1.0f ,

         1.0f, 1.0f, 1.0f, 1.0f ,
         1.0f, 1.0f, 1.0f, 1.0f ,
         1.0f, 1.0f, 1.0f, 1.0f 
    ;

    glUseProgram(shadptr->progGraphics);
    glBindVertexArray(vao_g);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_g);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, vertices, GL_DYNAMIC_DRAW);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    glUseProgram(shadptr->progText);
    glBindVertexArray(vao_t);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_t);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, vertices, GL_DYNAMIC_DRAW);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    SDL_GL_SwapWindow(winptr->window);


void set_buffers()

    glGenVertexArrays(1, &vao_g);
    glBindVertexArray(vao_g);

    glGenBuffers(1, &vbo_g);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_g);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);

    glGenVertexArrays(1, &vao_t);
    glBindVertexArray(vao_t);

    glGenBuffers(1, &vbo_t);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_t);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);

我有问题。不知道为什么在render函数中绑定vao后还要绑定vbo。当我不绑定 vbo 时,在 RenderDoc 中出现错误“glDrawArrays 已生成错误 (GL_OUT_OF_MEMORY)”,在网格输出中,在 VS 输入中我看到错误的值或 --- 值。

【问题讨论】:

“我不知道为什么我必须在渲染函数中绑定 vao 后绑定 vbo” - 因为您尝试通过以下方式创建和初始化缓冲区对象的数据存储glBufferData,为此必须绑定缓冲区。将此代码移至set_buffers,即可绑定顶点数组对象。 @Rabbid76 这可能应该作为答案而不是评论发布。 【参考方案1】:

不知道为什么在render函数中绑定vao后还要绑定vbo"

因为您尝试通过glBufferData 创建和初始化缓冲区对象的数据存储,因此必须绑定缓冲区。

我建议移动代码,它将创建缓冲区并将其初始化为set_buffers。那么只绑定顶点数组对象就足够了,在函数render中:

void render()

    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(shadptr->progGraphics);
    glBindVertexArray(vao_g);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    glUseProgram(shadptr->progText);
    glBindVertexArray(vao_t);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    SDL_GL_SwapWindow(winptr->window);

void set_buffers()

    ....

    GLfloat vertices[6][4] = 
         1.0f, 1.0f, 1.0f, 1.0f ,
         1.0f, 1.0f, 1.0f, 1.0f ,
         1.0f, 1.0f, 1.0f, 1.0f ,

         1.0f, 1.0f, 1.0f, 1.0f ,
         1.0f, 1.0f, 1.0f, 1.0f ,
         1.0f, 1.0f, 1.0f, 1.0f 
    ;

    glBindBuffer(GL_ARRAY_BUFFER, vbo_g);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, vertices, GL_DYNAMIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, vbo_t);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, vertices, GL_DYNAMIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, 0);


我建议使用glBufferSubData 来更改缓冲区的内容。这将更新缓冲区,但不会创建和初始化全新的数据存储,因此效率会更高。

【讨论】:

以上是关于VBO必须在VAO之后绑定的主要内容,如果未能解决你的问题,请参考以下文章

在绑定到一个 vao 的 vbo 之间切换

多个缓冲器和 VAO 性能

一个 VBO 可以绑定多个 VAO 吗?

VAO 与 VBO 和 IBO 的手动绑定

VAO 是不是同时记住 EBO/IBO(元素或索引)和 VBO?

顶点着色器 VAO 是不是需要 VBO?