【问题标题】:OpenGL Vertex Array Object usageOpenGL顶点数组对象使用
【发布时间】:2014-09-11 18:17:09
【问题描述】:

我一直在努力让 OpenGL 在场景中渲染多个不同的实体。

根据http://www.opengl.org/wiki/Vertex_Specification

顶点数组对象应该记住绑定到 GL_ARRAY_BUFFER、GL_ELEMENT_ARRAY_BUFFER 的顶点缓冲区对象。 (或者至少我是这样理解它在说什么的)

然而,即使我在绑定任何 vao 后调用 draw,应用程序也只会使用绑定到 GL_ARRAY_BUFFER 的最后一个。

问题 - 我理解正确吗?考虑下面的代码,所有调用 gl 函数的顺序都是正确的吗?

void OglLayer::InitBuffer()
{
    std::vector<float> out;
    std::vector<unsigned> ibOut;

    glGenVertexArrays(V_COUNT, vaos);
    glGenBuffers(B_COUNT, buffers);

    // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
    glBindVertexArray(vaos[V_PLANE]);

    PlaneBuffer(out, ibOut, 0.5f, 0.5f, divCount, divCount);

    OGL_CALL(glBindBuffer(GL_ARRAY_BUFFER, buffers[B_PLANE_VERTEX]));
    OGL_CALL(glBufferData(GL_ARRAY_BUFFER, out.size()*sizeof(float), out.data(), GL_DYNAMIC_DRAW));
    //GLuint vPosition = glGetAttribLocation( programs[P_PLANE], "vPosition" );
    OGL_CALL(glEnableVertexAttribArray(0));
    //OGL_CALL(glVertexAttribPointer( vPosition, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, BUFFER_OFFSET(0) ));
    OGL_CALL(glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, BUFFER_OFFSET(0) ));
    bufferData[B_PLANE_VERTEX].cbSize = sizeof(float) * out.size();
    bufferData[B_PLANE_VERTEX].elementCount = out.size()/3;
    OGL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[B_PLANE_INDEX]));
    OGL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibOut.size()*sizeof(unsigned), ibOut.data(), GL_STATIC_DRAW));
    bufferData[B_PLANE_INDEX].cbSize = sizeof(float) * ibOut.size();
    bufferData[B_PLANE_INDEX].elementCount = ibOut.size();

    // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
    glBindVertexArray(vaos[V_CUBE]);

    out.clear();
    ibOut.clear();

    GenCubeMesh(out, ibOut);

    glBindBuffer(GL_ARRAY_BUFFER, buffers[B_CUBE_VERTEX]);
    glBufferData(GL_ARRAY_BUFFER, out.size()*sizeof(float), out.data(), GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), BUFFER_OFFSET(0));
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[B_CUBE_INDEX]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned), ibOut.data(), GL_STATIC_DRAW);
}


void RenderPlane::Render( float dt )
{            
    // Putting any vao here always results in using the lastly buffer bound.
    OGL_CALL(glBindVertexArray(g_ogl.vaos[m_pRender->vao]));

    {
        OGL_CALL(glUseProgram(g_ogl.programs[m_pRender->program]));

        // uniform location
        GLint loc = 0;

        // Send Transform Matrix ( Rotate Cube over time )
        loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "transfMat");
        auto transf = m_pRender->pParent->m_transform->CreateTransformMatrix();
        glUniformMatrix4fv(loc, 1, GL_TRUE, &transf.matrix()(0,0));

        // Send View Matrix
        loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "viewMat");
        mat4 view = g_ogl.camera.transf().inverse();
        glUniformMatrix4fv(loc, 1, GL_TRUE, &view(0,0));

        // Send Projection Matrix
        loc = glGetUniformLocation(g_ogl.programs[m_pRender->program], "projMat");
        mat4 proj = g_ogl.camera.proj();
        glUniformMatrix4fv(loc, 1, GL_TRUE, &proj(0,0));
    }

    OGL_CALL(glDrawElements(GL_TRIANGLES, g_ogl.bufferData[m_pRender->ib].elementCount, GL_UNSIGNED_INT, 0));
}

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    GL_ARRAY_BUFFER 绑定不是 VAO 状态的一部分。您链接的 wiki 页面正确解释了这一点:

    注意:GL_ARRAY_BUFFER​绑定不是 VAO 状态的一部分!我知道这很令人困惑,但事实就是如此。

    另一方面,GL_ELEMENT_ARRAY_BUFFER 绑定是 VAO 状态的一部分。

    虽然我不完全不同意将其称为令人困惑,但如果您开始考虑它,它实际上是有道理的。 VAO 的目标是捕获通常在进行绘图调用之前设置的所有顶点状态。使用索引渲染时,这包括绑定用于绘制调用的正确索引缓冲区。因此,在 VAO 状态中包含 GL_ELEMENT_ARRAY_BUFFER 绑定是完全有意义的。

    另一方面,当前的GL_ARRAY_BUFFER 绑定根本不影响绘图调用。在调用glVertexAttribPointer() 之前建立正确的绑定很重要。而glVertexAttribPointer() 设置的所有状态都是 VAO 状态的一部分。因此 VAO 状态包含 每个属性 使用的顶点缓冲区引用,该引用由 glVertexAttribPointer() 调用建立。另一方面,当前的GL_ARRAY_BUFFER 不是 VAO 状态的一部分,因为绘制调用时的当前绑定对绘制调用没有任何影响。

    另一种看待这个问题的方式:由于用于绘制调用的属性可以从不同的顶点缓冲区中提取,因此在 VAO 状态中跟踪单个顶点缓冲区绑定将没有用处。另一方面,由于 OpenGL 只使用单个索引缓冲区进行绘制调用,并且使用当前索引缓冲区绑定进行绘制调用,因此在 VAO 中跟踪索引缓冲区绑定是有意义的。

    【讨论】:

    • 谢谢。现在一切都开始变得有意义了。
    • 只是为了澄清最后一段;因此,VAO 确实记得用作顶点属性的数据的位置(由客户端在 glVertexAttribPointer 调用中提供),但由于数据的位置可以来自各种来源(多个 VBO、客户端指针……),因此 VAO只记住一个恰好绑定到 GL_ARRAY_BUFFER 的 VBO 不会有任何用处。对吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多