我一直在努力让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));
}
答案 0 :(得分:2)
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中的索引缓冲区绑定是有意义的。