0

I've written a very basic .obj file loader (just loads the vertex coords and triangular face indices) and renderer. When I only load one model at a time, it works great. When I load a 2nd model (or more), each one draws itself and part of the others, and I've wracked my brain trying to figure out why this is.

This is a simple cyllinder being loaded and drawn

This is what happens when I load a cube and a cyllinder (cube first).

Some relevant code snippets:

This is where I open the .obj file and read the vertex coords and triangle face indices from the file.

bool Model::loadFromFile(string fileName)
{
    vector<GLfloat> vertices;
    vector<GLuint> indices;

    fstream file(fileName);

    string line = "";
    while (getline(file, line))
    {
        istringstream lineReader(line);
        char c;

        //read the first letter of the line
        //The first letter designates the meaning of the rest of the line
        lineReader >> c;

        vec3 vertex;        //if we need to read .x, .y, and .z from the file
        GLuint index[3];    //if we need to read the 3 indices on a triangle

        switch (c)
        {
        case '#':
            //we do nothing with comment lines
            break;

        case 'v': //V means vertex coords
        case 'V': //so Load it into a vec3
            lineReader >> vertex.x >> vertex.y >> vertex.z;
            vertices.push_back(vertex.x);
            vertices.push_back(vertex.y);
            vertices.push_back(vertex.z);
            break;

        case 'vt':
        case 'VT':
            //no tex coords yet either
            break;

        case 'f': //F means indices of a face
        case 'F':
            lineReader >> index[0] >> index[1] >> index[2];

            //we subtract one from each index in the file because
            //openGL indices are 0-based, but .obj has them as
            //1-based
            indices.push_back(index[0] - 1);
            indices.push_back(index[1] - 1);
            indices.push_back(index[2] - 1);

            cout << "Indices: " << index[0] << ", " << index[1] << ", " << index[2] << endl;
            break;
        }
    }

    return this->load(vertices, indices);
}

At the end of the loadFromFile method, the we pass in the vector of indices and vertices to the model::load() method, which creates and binds the VAO, VBO, and IBO.

bool Model::load(vector<float>& vertices, vector<GLuint>& indices)
{
    //create the VAO
    glGenVertexArrays(1, &handle);
    glBindVertexArray(getHandle());
    //and enable vertexPositionAttribute
    glEnableVertexAttribArray(pShader->getPositionAttribIndex());

    //Populate the position portion of the
    //VAO
    GLuint vboID = 0;
    glGenBuffers(1, &vboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), &vertices[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glVertexAttribPointer(pShader->getPositionAttribIndex(), 3, GL_FLOAT, GL_FALSE, 0, nullptr);

    //Populate the indices portion of the
    //VAO
    GLuint iboID = 0;
    glGenBuffers(1, &iboID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), &indices[0], GL_STATIC_DRAW);

    //bind nothing to avoid any mistakes or loading
    //of random data to my VAO
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    this->numVertices = vertices.size() / 3;
    this->numIndices = indices.size();

    cout << "Num Indices: " << numIndices << endl;

    return true;
}

Once the model is loaded, it's VAO id is stored in a class variable. The VAO is loaded in the model::bind() method.

void Model::bind()
{
    glBindVertexArray(getHandle());
}

And drawn with a call to glDrawElements()

void Model::draw()
{
    //and draw me, bitchez!
    glDrawElements(GL_TRIANGLES, this->numIndices, GL_UNSIGNED_INT, nullptr);
}

The models are drawn inside the level::draw() method:

void Level::draw()
{
    pShader->setViewMatrix(camera.getViewMatrix());

    for (int modelIndex = 0; modelIndex < models.size(); modelIndex++)
    {
        models[modelIndex]->bind();

        for (int drawableIndex = 0; drawableIndex < drawables.size(); drawableIndex++)
            drawables[drawableIndex]->draw();
    }
}

There are no OpenGL errors, and the file parsing churns out the right values when I print it to the console.

If anyone can point out how/why this is happening, I would greatly appreciate it.

Daniel
  • 71
  • 4

1 Answers1

0

Well, after a few more hours of digging through code, I noted inside the level::draw method:

for (int modelIndex = 0; modelIndex < models.size(); modelIndex++)
{
    models[modelIndex]->bind();

    for (int drawableIndex = 0; drawableIndex < drawables.size(); drawableIndex++)
        drawables[drawableIndex]->draw();
}

I bind the VAO of every model for every entity I load. Quite literally I was drawing every loaded model for everything on screen. Sorry to waste screen space on the OpenGL section with this!

Daniel
  • 71
  • 4