Loading model with multiple objects from .obj file

Hello, sorry if this question was asked here before, but i’ve searched everywhere and didn’t found anything similar to my problem. I have a 3D model in .obj file and i managed to successfully load it in my project. Problem is, my problem is complex and i need to interact with different parts of it, but i know only how to load it in one go, as single object. In my understanding, i need to separate it by object names during loop, but i failed to found any example of proper parsing files with multiple objects, every article i found completely ignores existing of ‘o’ tag, so maybe it’s not the right way to do this and i’m missing something? The other problem that even if i’ll somehow manage to load multiple objects, does this mean that i also need to create multiple vertex and index buffers or should i store everything in single buffers? From what i’ve read, it’s impossible to bind two or more buffers at the same time, but then how to allocate points for different objects in one buffer correctly? I’m using Qt, this is how my object class looks like:

class SceneObject
{
public:
SceneObject();
typedef struct {
    QVector3D vertex;
    QVector3D normal;
    QVector2D texcoord;
} Point;

typedef unsigned int PointIdxType;
const GLuint GLPointIdxType = GL_UNSIGNED_INT;

typedef unsigned int FaceIdxType;

QVector<QVector3D> vertices;
QVector<QVector3D> face_normal;
QVector<QVector2D> texcoords;
QVector<Point> points;
QHash<QString,PointIdxType> string_to_point_index;
QVector<PointIdxType> faces_points_indices;
QVector<QVector<FaceIdxType> > point_faces;

QList<SceneObject *> objects;

QGLBuffer vertex_buffer;
QGLBuffer *index_buffer;

void loadObjModel(QString path);
};

Using SceneObject in initializeGL()

curObj = new SceneObject;

if (curObj->vertex_buffer.create())
{
    curObj->vertex_buffer.bind();
    curObj->vertex_buffer.setUsagePattern(QGLBuffer::StaticDraw);
    curObj->vertex_buffer.release();
}
else qDebug() << "Couldn't create vertex_buffer";

curObj->index_buffer = new QGLBuffer(QGLBuffer::IndexBuffer);
if (curObj->index_buffer&&(curObj->index_buffer->create()))
{
    curObj->index_buffer->bind();
    curObj->index_buffer->setUsagePattern(QGLBuffer::StaticDraw);
    curObj->index_buffer->release();
}
else qDebug() << "Couldn't create index_buffer";

curObj->loadObjModel("model.obj");

Using SceneObject in painGL()

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

curObj->vertex_buffer.bind();
curObj->index_buffer->bind();
glVertexPointer(3,GL_FLOAT,sizeof(SceneObject::Point),0);
glNormalPointer(GL_FLOAT,sizeof(SceneObject::Point),(void*)12);
glTexCoordPointer(2,GL_FLOAT,sizeof(SceneObject::Point),(void*)24);

glDrawElements(GL_TRIANGLES,curObj->faces_points_indices.count(),curObj->GLPointIdxType,0);
curObj->index_buffer->release();
curObj->vertex_buffer.release();

glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

loadObjModel structure

vertices.clear();
texcoords.clear();
string_to_point_index.clear();
points.clear();
point_faces.clear();
face_normal.clear();
faces_points_indices.clear();


***
reading obj file and appending data
***


vertex_buffer.bind();
vertex_buffer.allocate(points.constData(),points.count()*sizeof(Point));
vertex_buffer.release();

index_buffer->bind();
index_buffer->allocate(faces_points_indices.constData(),faces_points_indices.count()*sizeof(PointIdxType));
index_buffer->release();

During parsing, you need to track the “current” object. An “o” command changes the current object. A “f” command appends a face to the current object. Vertices, texture coordinates and normals don’t inherently belong to a specific object; a single vertex can be referenced from faces in different objects. The faces for a single object aren’t necessarily contiguous; an “o” command doesn’t have to refer to a new object, it can refer to an object for which faces have already been appended.

So you probably want a dictionary (e.g. QHash) which maps object names to IDs, a current object ID, and a vector of vectors which hold the faces for each object. Processing an “o” command would look up the ID (or allocate a new one) and store it; processing a “f” command would append the face to the vector for the current object. The handling of vertex attributes would be unaffected by support for multiple objects.

Different objects can use different index buffers or different regions of a single index buffer. They can even use different vertex buffers if you duplicate vertices which are used by multiple objects (although there’s no inherent reason to do this). Personally, I’d tend to use a single buffer for everything (unless some of the data was going to be modified after loading). With a single buffer (or at least a single buffer for each attribute), you can use glMultiDrawElements() to draw multiple objects in one operation.

If you’re planning on using materials (“usemtl” command), things get a bit more complex.