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.
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.