Search code examples
c++openglvectorwavefront

Loading obj files in openGL


I'm new to OpenGL and I'm trying to load obj files into my code. I have a code of a simple animating cube. When I declare the vertices and indices as follows it works properly:

GLfloat cube_vertices[] = {
// front
    -1.0, -1.0, 1.0,
    1.0, -1.0, 1.0,
    1.0, 1.0, 1.0,
    -1.0, 1.0, 1.0,
    // back
    -1.0, -1.0, -1.0,
    1.0, -1.0, -1.0,
    1.0, 1.0, -1.0,
    -1.0, 1.0, -1.0,
};
GLushort cube_elements[] = {
    // front
    0, 1, 2,
    2, 3, 0,
    // top
    1, 5, 6,
    6, 2, 1,
    // back
    7, 6, 5,
    5, 4, 7,
    // bottom
    4, 0, 3,
    3, 7, 4,
    // left
    4, 5, 1,
    1, 0, 4,
    // right
    3, 2, 6,
    6, 7, 3,
};

However, when I'm trying to get similar number from a file, the program runs without error but shows nothing in the window. Here is my code for loading the obj file:

vector<GLfloat> vertices;
vector<GLushort> elements;

ifstream in("cube.obj", ios::in);
if (!in)
{
    cerr << "Cannot open " << "sample.obj" << endl; exit(1);
}

string line;
while (getline(in, line))
{
    if (line.substr(0, 2) == "v ")
    {
        istringstream s(line.substr(2));
        GLfloat v;
        s >> v; vertices.push_back(v);
        s >> v; vertices.push_back(v);
        s >> v; vertices.push_back(v);

    }
    else if (line.substr(0, 2) == "f ")
    {
        istringstream s(line.substr(2));
        GLushort a, b, c;
        s >> a; s >> b; s >> c;
        elements.push_back(a); elements.push_back(b); elements.push_back(c);
    }
}

The cube.obj file is saved as follows:

o cube
v -1.0 -1.0 1.0
v 1.0 -1.0 1.0
v 1.0 1.0 1.0
v -1.0 1.0 1.0
v -1.0 -1.0 -1.0
v 1.0 -1.0 -1.0
v 1.0 1.0 -1.0
v -1.0 1.0 -1.0
f 0 1 2
f 2 3 0
f 1 5 6
f 6 2 1
f 7 6 5
f 5 4 7
f 4 0 3
f 3 7 4
f 4 5 1
f 1 0 4
f 3 2 6
f 6 7 3

I'm just getting a blank window in the output. Do you have any idea why the loader doesn't work?

I upload the data thus

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), &elements, GL_STATIC_DRAW);

When I don't put the & operator before vertices and elements it gives compilation error of "no suitable conversion".


Solution

  • glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW);
    

    glBufferData expects the raw data and not the vector directly, also the size of this data should be given correctly. What you are doing here is passing the size of the vector itself and not the data it contains.

    A vector is a data structure, a container, with metadata like a pointer to the data it's going to hold and a variable to hold the count of element it holds. When you do sizeof(vector) it would always return a constant number, irrespective of the number of elements it houses; this size is the sizeof(pointer-to-data) + sizeof(variable-holding-count). This data is not what you want.

    Also, when you pass &vertices, you are passing the address of the vector itself and not the address of the data it contains. vector::data() gives the address of the data contained inside it.

    Instead do this:

    glBufferData(GL_ARRAY_BUFFER,
                 vertices.size() * sizeof(GLfloat),
                 vertices.data(),
                 GL_STATIC_DRAW);
    

    should do it. The same goes for element array buffer too.

    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                 elements.size() * sizeof(GLushort),
                 elements.data(),
                 GL_STATIC_DRAW);
    

    vector::size() gives the count of the elements it contains, that times the size of one element gives the right size of the data contained.

    Aside

    line.substr(0, 2) == "v "
    line.substr(0, 2) == "f "
    

    This would create two substrings unnecessarily, instead you could do this to check the same thing

    line[0] == 'v'
    line[0] == 'f'