在逐个加载对象时,OpenGL索引缓冲区无法正常工作

时间:2017-04-26 17:06:50

标签: c++ opengl index-buffer

我正在学习OpenGL并遇到了“障碍”。 我使用索引缓冲区绘制了一些房屋(块和金字塔)。 当将所有顶点(从所有房屋)加载到顶点缓冲区并使用一个大索引缓冲区时,这可以正常工作。现在我想对对象进行动画处理并将它们逐个加载到顶点缓冲区中,这样我就可以逐个对对象执行转换。代码与一个大缓冲区没有太大区别,但是当我这样做时,我只看到一些随机形状在屏幕上拍摄。我的代码如下:

我有一个包含3D对象列表的世界类,有一个所有顶点的大列表(用于试验目的),一个大的索引列表(也是试验)和一个向世界添加Object3D对象的方法。

class World
{
public:
World();
~World();

vector<Object3D> objects;
vector<glm::vec3> Vertices;
vector<GLushort> Indices;

void AddObject(Object3D &object);

};

Object3D类:

class Object3D
{
public:
Object3D();
~Object3D();

glm::vec3 Position;
vector<glm::vec3> Vertices;
vector<unsigned int> Indices;
};

World AddObject方法,只需将对象添加到“对象”列表中,并将顶点和索引添加到“顶点”和“索引”列表中,以创建一个大缓冲区:

void World::AddObject(Object3D &object) {

int oldVerticesSize = Vertices.size();
objects.push_back(object);
Vertices.insert(Vertices.end(), object.Vertices.begin(), object.Vertices.end());

for each (GLushort index in object.Indices)
{
    Indices.push_back(index + oldVerticesSize);
}
}

当我使用所有顶点和索引渲染大缓冲区时(如下所示),它可以正常工作。

void WorldRenderer::Render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindVertexArray(Vao); //use vao
glDrawElements(GL_TRIANGLES, World.Indices.size(), GL_UNSIGNED_SHORT, 0);
//glDrawArrays(GL_TRIANGLES, 0, World.Vertices.size());
glBindVertexArray(0); //release vao

//Model = glm::rotate(Model, 0.01f, glm::vec3(0.0f, 1.0f, 0.0f));
Mvp = Projection * View * Model;

glUniformMatrix4fv(UniformMvp, 1, GL_FALSE, glm::value_ptr(Mvp));
glutSwapBuffers();

//glutPostRedisplay();

}

当我循环遍历对象并一次一个对象地加载缓冲区中对象的顶点时(如下所示),它显示了一些随机的“形状”,它们可以“射击”或快速变化。我在这做错了什么? 提前感谢任何建议。

void WorldRenderer::Render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

int index = 0;
for each (Object3D mesh in World.objects)
{
    Mvp = Projection * View * Model;

    UpdateBuffer(mesh.Vertices, mesh.Indices);

    glBindVertexArray(Vao); //use vao
    glDrawElements(GL_TRIANGLES, mesh.Indices.size() , GL_UNSIGNED_SHORT, 0);
    glBindVertexArray(0); //release vao
    glUniformMatrix4fv(UniformMvp, 1, GL_FALSE, glm::value_ptr(Mvp));
    index++;
}

glutSwapBuffers();
}

UpdateBuffers方法:

void WorldRenderer::UpdateBuffer(vector<glm::vec3> vertices, vector<unsigned int> indices) {

//fill Vbo
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size(), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

//fill ibo
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

glBindVertexArray(Vao);
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
}

对于第一个Render方法(没有循环),缓冲区在init方法中创建一次,如下所示:

void WorldRenderer::Init(int argc, char ** argv) {
InitGlutGlew(argc, argv);
InitMatrices();

glDisable(GL_CULL_FACE);
//-------------- init buffers --------------
// vbo vertices
glGenBuffers(1, &Vbo);
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBufferData(GL_ARRAY_BUFFER, World.Vertices.size() * sizeof(glm::vec3),
    &World.Vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//ibo
glGenBuffers(1, &Ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, World.Indices.size() * sizeof(unsigned int),
    &World.Indices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

// VAO setup
glGenVertexArrays(1, &Vao);
glBindVertexArray(Vao);
// Bind vertices to vao
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
//Bind elements
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);

//------ init shaders -----------
InitShader();
}

1 个答案:

答案 0 :(得分:2)

只要我看到您的UpdateBuffer功能,我就认为glBufferData的{​​{1}}未正确加载。

第二个参数vbo仅返回向量中的元素数,但不返回对象的实际大小。

所以第二个参数应该是vertices.size()

第三个参数是ok,因为它返回指向底层数组的指针。如果不工作....直接传递第一个元素的地址,如下所示。

总的来说,它应该如下所示。

vertices.size() * sizeof(glm::vec3)

检查它是否有效。

为什么会看到差异?

首先渲染:

当调用glBufferData( GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW ); 时,缓冲区会连续包含所有世界的顶点数据。 所以这里 mesh1最后一个顶点继续使用网格2拳头顶点 ....所以你看到一种封闭的形状。

第二次渲染:

当调用glDrawElements时,缓冲区一次只包含一个网格数据。

所以在调用glDrawElements后,每个网格的形状都会结束。

要获得与第一次渲染相同的结果,您必须首先为所有网格更新单个顶点缓冲区(使用glDrawElements)。

然后拨打glBufferSubData一次。然后你会看到相同的结果。