openGL 3.3-使用glDrawArrays/glDrawElements的VBO绘图

openGL 3.3 - VBO drawing with glDrawArrays / glDrawElements

本文关键字:glDrawElements VBO 绘图 glDrawArrays 使用 openGL      更新时间:2023-10-16

我将VC++2010与GLFW3和GLEW一起用于openGL。我已经制作了一个OBJ加载器来加载三角网格。在某个时刻,我在VBOMesh2对象中填充以下数组。

GLfloat *vertices;
GLfloat *normals;
GLuint *indices;

因此,我得到了我用于VBO:的数据

  • 顶点:顶点=[v0x,v0y,v0z,v1x,v1y,v1z,…]
  • (已排序)法线:法线=[n0x,n0y,n0z,n1x,n1y,n1z,…]
  • 索引:inices={face0i0,face0i1,face0i2,face1i0,face1i1,face1i2,…]

下一步是使用VBOMesh2对象中的init()-method绑定Buffers。vertexVBOID、normalsVBOID和indexVBOID是GLuint。

void VBOMesh2::init(void)
{
    vertexVBOID = 0;
    glGenBuffers(1, &vertexVBOID);
    glBindBuffer(GL_ARRAY_BUFFER, vertexVBOID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*numFaces*3*3, vertices, GL_STATIC_DRAW);
    normalsVBOID = 0;
    glGenBuffers(1, &normalsVBOID);
    glBindBuffer(GL_ARRAY_BUFFER, normalsVBOID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*numFaces*3*3, normals, GL_STATIC_DRAW);
    indexVBOID = 0;
    glGenBuffers(1, &indexVBOID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBOID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*numFaces*3, indices, GL_STATIC_DRAW);
}

好的。。。我用画画

void VBOMesh2::draw(void)
{
    glEnableClientState(GL_VERTEX_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, vertexVBOID);
    glVertexPointer(3, GL_FLOAT, sizeof(float)*3, 0);
    glEnableClientState(GL_NORMAL_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, normalsVBOID);
    glNormalPointer(GL_FLOAT, sizeof(float)*3, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBOID);
    glPushMatrix();
    glTranslatef(x, y, z);
    glRotatef(rx, 1, 0, 0);
    glRotatef(ry, 0, 1, 0);
    glRotatef(rz, 0, 0, 1);
    glDrawArrays(GL_TRIANGLES, indices[0], numIndices);
    glPopMatrix();
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
}

我可以用加载网格

OBJLoader objLoader;
MeshData meshData;
objLoader.loadFile("temp/quad_smooth.obj");
meshData = objLoader.getMeshData();
VBOMesh2 tmpMesh(meshData);

并用绘制(在openGL循环中)

tmpMesh.draw();

我得到以下结果:

一个四元

太棒了!

现在我想,让我们用以下代码画500个四边形:

OBJLoader objLoader;
MeshData meshData;
objLoader.loadFile("temp/quad_smooth.obj");
meshData = objLoader.getMeshData();
for(int i = 0; i < 500; i++)
{
   VBOMesh2 tmpMesh(meshData);
   meshes.push_back(tmpMesh);
   meshes[i].init();
 // Do stuff for position and rotation like meshes[i].setX(x); and so on
}

在openGL循环中,我做:

for(int i = 0; i < meshes.size(); i++) 
{
   meshes[i].draw();
}

顺便说一句。网格是一个向量:

vector<VBOMesh2> meshes;

我得到了以下结果:

500 Quads

哦,不!!!

现在我不知道为什么我的网格(不是全部,而是一些)被破坏了。。。或者我做错了什么。。。。该代码可以在没有任何可视化错误的情况下渲染一个四边形,但当我使用相同的meshData创建500个四边形时(来自oneQuad的相同数据),我得到了损坏的四边形。。。。

而不是使用

glDrawArrays(GL_TRIANGLES, indices[0], numIndices);

我试过

glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, 0);

为此,我用其他方法填充了数组的顶点、法线和索引(如果需要,我可以发布),但我遇到了同样的问题。。。我可以画一个Quad而没有错误,但当我试图画500个Quad时,我得到了访问违规0x000005。

Btw。我更新了我的显卡驱动程序(但问题仍然存在)

有人能给我一个提示吗?

不要使用std::vector<VBOMesh2>,因为矢量对值进行运算。如果您已经实现了~VBOMesh2来删除数组,那么您可能正在绘制悬挂指针(即indices[0])。请使用VBOMesh2std::vector<VBOMesh2*>的简单数组。

glDrawArrays(GL_TRIANGLES, indices[0], numIndices);

这不是绘制索引网格的方法。第二个参数是前面用glVertexPointerglNormalPointer绑定的数组的偏移量。在您的情况下,它应该始终为0。

你需要决定是否要使用索引网格,你的问题还不清楚。如果需要,则需要使用glDrawElements。但是,顶点和法线数据的大小不正确。但我怀疑你知道这一点。看起来有点像是您第一次实现了索引网格的代码,当它不起作用时,您尝试将其转换为非索引网格。