简体   繁体   English

OpenGL顶点阵列对象用法

[英]OpenGL Vertex Array Object usage

I have been working to get OpenGL to render multiple different entities on the scene. 我一直在努力使OpenGL在场景上渲染多个不同的实体。

According to http://www.opengl.org/wiki/Vertex_Specification , 根据http://www.opengl.org/wiki/Vertex_Specification

Vertex Array Object should remember what Vertex Buffer Object was bound to GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER. 顶点数组对象应记住将哪个顶点缓冲区对象绑定到GL_ARRAY_BUFFER,GL_ELEMENT_ARRAY_BUFFER。 (Or at least that is how I understood what it was saying) (或者至少这就是我所理解的意思)

Yet, even though I call draw after binding any vao, the application will use only the last one bound to GL_ARRAY_BUFFER. 但是,即使我在绑定任何vao之后都调用draw,该应用程序也只会使用绑定到GL_ARRAY_BUFFER的最后一个。

Question - Am I understanding it right? 问题-我理解正确吗? Considering the code below, is all sequence of calling to gl functions is correct? 考虑下面的代码,所有调用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));
}

The GL_ARRAY_BUFFER binding is not part of the VAO state. GL_ARRAY_BUFFER绑定不是 VAO状态的一部分。 The wiki page you link explains that correctly: 您链接的Wiki页面正确解释了这一点:

Note: The GL_ARRAY_BUFFER​ binding is NOT part of the VAO's state! 注意:GL_ARRAY_BUFFER绑定不是VAO状态的一部分! I know that's confusing, but that's the way it is. 我知道这很令人困惑,但这就是事实。

The GL_ELEMENT_ARRAY_BUFFER binding on the other hand is part of the VAO state. 另一方面, GL_ELEMENT_ARRAY_BUFFER绑定是VAO状态的一部分。

While I don't completely disagree with calling this confusing, it actually does make sense if you start thinking about it. 尽管我并不完全不同意这种混淆,但是如果您开始考虑它,这的确有意义。 The goal of a VAO is to capture all vertex state that you would typically set up before making a draw call. VAO的目标是捕获在进行绘制调用之前通常应设置的所有顶点状态。 When using indexed rendering, this includes binding the proper index buffer used for the draw call. 使用索引渲染时,这包括绑定用于绘图调用的适当索引缓冲区。 Therefore, including the GL_ELEMENT_ARRAY_BUFFER binding in the VAO state makes complete sense. 因此,在VAO状态下包含GL_ELEMENT_ARRAY_BUFFER绑定是完全有意义的。

On the other hand, the current GL_ARRAY_BUFFER binding does not influence a draw call at all. 另一方面,当前的GL_ARRAY_BUFFER绑定完全不影响绘图调用。 It only matters that the correct binding is established before calling glVertexAttribPointer() . 只需要在调用glVertexAttribPointer()之前建立正确的绑定就可以了。 And all the state set by glVertexAttribPointer() is part of the VAO state. glVertexAttribPointer()设置的所有状态都是 VAO状态的一部分。 So the VAO state contains the vertex buffer reference used for each attribute , which is established by the glVertexAttribPointer() call. 因此,VAO状态包含用于每个属性的顶点缓冲区引用,该引用由glVertexAttribPointer()调用建立。 The current GL_ARRAY_BUFFER on the other hand is not part of the VAO state because the current binding at the time of the draw call does not have any effect on the draw call. 另一方面,当前的GL_ARRAY_BUFFER不属于VAO状态,因为在绘制调用时当前的绑定对绘制调用没有任何影响。

Another way of looking at this: Since attributes used for a draw call can be pulled from different vertex buffers, having a single vertex buffer binding tracked in the VAO state would not be useful. 另一种看待这种情况的方式:由于可以从不同的顶点缓冲区中提取用于绘制调用的属性,因此在VAO状态下跟踪单个顶点缓冲区绑定将无用。 On the other hand, since OpenGL only ever uses a single index buffer for a draw call, and uses the current index buffer binding for the draw call, tracking the index buffer binding in the VAO makes sense. 另一方面,由于OpenGL仅对绘制调用使用单个索引缓冲区,而对绘制调用使用当前索引缓冲区绑定,因此在VAO中跟踪索引缓冲区绑定是有意义的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM