1

I'm learning OpenGL and ran into an "obstacle". I drew some houses (blocks and pyramids) using an indexbuffer. This works fine when loading all the vertices (from all houses) into the vertexbuffer and using 1 big indexbuffer. Now I want to animate the objects and load them in the vertexbuffer one by one so I can execute transformation on the objects one by one. The code is not much different from one big buffer, but when I do this I just see some random shapes shooting around on the screen. My code is as follows:

I have a world class which holds the list of 3D objects, has one big list of all vertices (for trial purposes), one big list of indices (also trial) and a method to add an Object3D object to the world.

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

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

void AddObject(Object3D &object);

};

Object3D class:

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

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

World AddObject method, simply adds the object to the "objects" list and adds the vertices and indices to the "Vertices" and "Indices" lists to create one big buffer:

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);
}
}

When I render the big buffer with all the vertices and indices (as shown below) it works fine.

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();

}

When I loop through the objects and load the vertices of the objects in the buffer one-object-at-a-time (as shown below) it shows some random "shapes" which keep "shooting around" or rapidly changing. What am I doing wrong here? Thanks in advance for any advice.

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 method:

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);
}

For the first Render method (without the loop) the buffers are created once in the init method which looks like this:

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 Answers1

2

As soon as I see your UpdateBuffer function, I feel that the glBufferData for vbo is not loaded properly.

The second parameter vertices.size() returns just number of elements in vector but not the actual size of object.

So the second parameter should be vertices.size() * sizeof(glm::vec3)

And the third parameter is ok as it returns pointer to the underlying array. If not working ....directly pass the address of first element as shown below.

Overall it should be something like as shown below.

glBufferData(
   GL_ARRAY_BUFFER,
   vertices.size() * sizeof(glm::vec3),
   &vertices[0],
   GL_STATIC_DRAW
);

Check if it works.

Why you are seeing differences?

First render:

Your buffer contain all the world's data for vertices continuosly, when the glDrawElements is called. So here the mesh1 last vertex is continued with mesh 2 fist vertex.... So you see a kind of closed shape.

Second render:

your buffer contains only one mesh data at a time, when the glDrawElements is called.

so your shape ends for each mesh after calling glDrawElements.

To obtain the same result as first render, you have to first update a single vertex buffer for all meshes ( use glBufferSubData).

Then call glDrawElements once. Then you will see same result.

Pavan Chandaka
  • 11,671
  • 5
  • 26
  • 34
  • Thanks! :D That got me a step further (I should be more tidy). However now I only see around half of the triangles I draw. The indexbuffer and vertexbuffer seem fine and I tried moving some indexes around and disable Cull face, but I keep seeing the same triangles of each mesh. Any idea why it's like that? Image good: https://puu.sh/vwZAc/e108f7fb9c.png. Image not good: https://puu.sh/vx0j6/a8eddd1d7d.png – Sebastiaan Hoedeman Apr 26 '17 at 18:02
  • try releasing " glBindVertexArray(0); //release vao" outside the loop.... I mean after for each loop....in the function "Render()" – Pavan Chandaka Apr 26 '17 at 18:29
  • That doesn't seem to work :\. Also tried glBindVertexArray(Vao) outside the loop (which seems logical then), but no change unfortunately. – Sebastiaan Hoedeman Apr 26 '17 at 18:35
  • glBindVertexArray(Vao) should be inside loop only as you want "Vao" for each mesh of world.objects... Just have "glBindVertexArray(0);" alone outside the loop. Could you please post, how you created "Vao" for good "render()" function.... I mean the "Vao" in first render function, where loop does not exist. – Pavan Chandaka Apr 26 '17 at 18:42
  • I added the code where the buffers are created and filled once for both render methods. The first render method (without the loop) doesn't change them and just renders them. In the second Render method (with the loop) the data is overriden with the data for each mesh. I already tried only putting glBindVertexArray(Vao) inside the loop and glBindVertexArray(0) outside, but it dind't change anything unfortunately. – Sebastiaan Hoedeman Apr 26 '17 at 19:32
  • Updated the answer. Please look into it. – Pavan Chandaka Apr 26 '17 at 21:06
  • Thanks that's an option I will keep my mind on, but in this case even one single Mesh object isn't drawn completely. Each house consists of a cube and a pyramid which are two meshes. Both meshes are drawn half it seems even though the entire cube its vertices and indexes are loaded in the buffers. If I work with just one Mesh (a cube e.g.) it still only draws half of the cube. I read some articles and posts which said loading different VBO's (one per Mesh e.g.) is fine which is what I'm doing here. If I just can't get this to work I'll try one buffer, but I'm at least curious in this. – Sebastiaan Hoedeman May 02 '17 at 17:00
  • I guess you add each mesh using Object3D object. Double check there it self whether your vertices are proper or not in each object of Object3D (mesh). Because the later portion of the code is.. just indicating frame buffer to draw "these vertices in this format"..... – Pavan Chandaka May 02 '17 at 17:15