framerate issues with my obj loader

Started by
8 comments, last by Argo15 13 years, 11 months ago
I have just recently finished my wavefront obj loader. I already know that obj isn't a very efficient file format and neither is my parsing/drawing code. But When i load and draw a model with these stats: 7958 Verts 7871 Normals 0 Texture Coords 7872 faces I get a framerate of only 43 fps. I have a pretty beefy system so I was expecting better. I know that I can run commercial games that render a lot more. I guess I'm just asking for generic hints right now, but if your willing to give additional help, i will post my source code.
Advertisement
You should definitely post code, I'm sure you can get some help here.

You're right that its not a terribly efficient format to load, but this should be a one time hit when program loads and shouldn't effect your framerate.

The methods you use to draw the data will matter a lot though. Are you by chance using immediate mode drawing (glBegin/glEnd)? This is a very slow method and should not be used, the proper method of drawing is to use Vertex Buffer Objects (VBO).

I'm sure we can give more specific advice once we see your rendering code.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
I think you're confusing loading with rendering (or something). It really doesn't make much sense to say that OBJ isn't an 'efficient' format - not in this context at least - because once you've loaded the model data, you can put it in whatever form you want for rendering purposes. In other words, OBJ might be slow for *loading*, but the fact that you're using OBJ shouldn't have any bearing on your frame rate.

As for rendering the model, in the absence of further information I would say that your best bet is to load the model data into a VBO and render from there.

How are you rendering the model currently?
Quote:Original post by karwosts
You should definitely post code, I'm sure you can get some help here.

You're right that its not a terribly efficient format to load, but this should be a one time hit when program loads and shouldn't effect your framerate.

The methods you use to draw the data will matter a lot though. Are you by chance using immediate mode drawing (glBegin/glEnd)? This is a very slow method and should not be used, the proper method of drawing is to use Vertex Buffer Objects (VBO).

I'm sure we can give more specific advice once we see your rendering code.


Okay, here is objLoader.h

#include <gl/gl.h>#include <iostream>#include <fstream>#include <string>using namespace std;string getValues(char Char, string line);struct Vertex{    float x, y, z;    int indexNum;};struct Normal{    float x,y,z;    int indexNum;};struct texCoord{    float U, V;    int indexNum;};struct Face{    int v1, v2, v3, v4;    int n1, n2, n3, n4;    int uv1, uv2, uv3, uv4;    Face operator = (const Face &param);};class objModel{    public:        objModel();        bool Load(char* filename);        void Draw();    private:        Vertex *pVerts;        Normal *pNorms;        texCoord *pUVs;        Face *pfaces;        int nVerts, nNorms, nUVs, nFaces;        char *filename;        void getVert(string line, float &x, float &y, float &z);        void getNorm(string line, float &x, float &y, float &z);        void getUV(string line, float &x, float &y);        Face getFace(string line);        int fileLines(char* filename);        void numVertNormUVFace(char *filename, int &verts, int &norms, int &UVs, int &faces);};

and here is objLoader.cpp

#include "ObjLoader.h"objModel::objModel(){}int objModel::fileLines(char* filename){    int size = 0;    string* line = new string;    ifstream inData;    inData.open(filename);    if (!inData)        return 0;    if (inData.is_open())    {        while (!inData.eof())        {            getline(inData, *line);            size++;        }        inData.close();    }    delete line;    return size;}void objModel::numVertNormUVFace(char *filename, int &verts, int &norms, int &UVs, int &faces){    ifstream data;    string tmp;    data.open(filename);    if (data.is_open())    {        while (!data.eof())        {            getline(data, tmp);            if(tmp[0] == 'v' && tmp[1] == ' ') { verts++; }            if(tmp[0] == 'v' && tmp[1] == 't') { UVs++;   }            if(tmp[0] == 'v' && tmp[1] == 'n') { norms++; }            if(tmp[0] == 'f' && tmp[1] == ' ') { faces++; }        }        data.close();    }}void objModel::getVert(string line, float &x, float &y, float &z){    string vString[3];    int c = 0;    for (int i = 2; i <= line.size(); i++)    {        if (line == ' ')        {            c++;        }        else        {            vString[c].push_back(line);        }    }    x = (float)atof(vString[0].c_str());    y = (float)atof(vString[1].c_str());    z = (float)atof(vString[2].c_str());}void objModel::getNorm(string line, float &x, float &y, float &z){    string vString[3];    int c = 0;    for (int i = 3; i <= line.size(); i++)    {        if (line == ' ')        {            c++;        }        else        {            vString[c].push_back(line);        }    }    x = (float)atof(vString[0].c_str());    y = (float)atof(vString[1].c_str());    z = (float)atof(vString[2].c_str());}void objModel::getUV(string line, float &x, float &y){    string vString[2];    int c = 0;    for (int i = 3; i <= line.size(); i++)    {        if (line == ' ')        {            c++;        }        else        {            vString[c].push_back(line);        }    }    x = (float)atof(vString[0].c_str());    y = (float)atof(vString[1].c_str());}Face objModel::getFace(string line){    string fString[4];    int c = 0;    for (int i = 2; i < line.size(); i++)    {        if (line == ' ')        {            c++;        }        else        {            fString[c].push_back(line);        }    }    string s1[3][4];    c = 0;    for (int x = 0; x < 4; x++)    {        for (int i = 0; i < fString[x].size(); i++)        {            if (fString[x].at(i) == '/')            {                c++;            }            else            {                s1[c][x].push_back(fString[x].at(i));            }        }        c = 0;    }    Face f;    f.v1 = atoi(s1[0][0].c_str());    f.v2 = atoi(s1[0][1].c_str());    f.v3 = atoi(s1[0][2].c_str());    f.v4 = atoi(s1[0][3].c_str());    f.uv1 = atoi(s1[1][0].c_str());    f.uv2 = atoi(s1[1][1].c_str());    f.uv3 = atoi(s1[1][2].c_str());    f.uv4 = atoi(s1[1][3].c_str());    f.n1 = atoi(s1[2][0].c_str());    f.n2 = atoi(s1[2][1].c_str());    f.n3 = atoi(s1[2][2].c_str());    f.n4 = atoi(s1[2][3].c_str());    return f;}bool objModel::Load(char* Filename){    filename = Filename;    nVerts = nNorms = nUVs = nFaces = 0;    string tmp;    numVertNormUVFace(filename, nVerts, nNorms, nUVs, nFaces);    cout << "In the file " << filename << " there are:" << endl;    cout << nVerts << " Vertices." << endl;    cout << nNorms << " Normals." << endl;    cout << nUVs << " Texture Coordnates." << endl;    cout << nFaces << " Polygons." << endl;    pVerts = new Vertex[nVerts];    pUVs = new texCoord[nUVs];    pNorms = new Normal[nNorms];    pfaces = new Face[nFaces];    int vLoop = 0;    int nLoop = 0;    int tLoop = 0;    int fLoop = 0;    ifstream file(filename);    if (file.is_open())    {        while (!file.eof())        {            getline(file, tmp);            if (tmp[0] == 'v' && tmp[1] == ' ')            {                getVert(tmp, pVerts[vLoop].x, pVerts[vLoop].y, pVerts[vLoop].z);                pVerts[vLoop].indexNum = vLoop;                vLoop++;            }            if (tmp[0] == 'v' && tmp[1] == 'n')            {                getNorm(tmp, pNorms[nLoop].x, pNorms[nLoop].y, pNorms[nLoop].z);                pNorms[nLoop].indexNum = nLoop;                nLoop++;            }            if (tmp[0] == 'v' && tmp[1] == 't')            {                getUV(tmp, pUVs[tLoop].U, pUVs[tLoop].V);                pUVs[tLoop].indexNum = tLoop;                tLoop++;            }            if (tmp[0] == 'f' && tmp[1] == ' ')            {                pfaces[fLoop] = getFace(tmp);                fLoop++;            }        }        file.close();    }    return true;}void objModel::Draw(){    glBegin(GL_QUADS);    for (int f = 0; f < nFaces; f++)    {        glVertex3f(pVerts[pfaces[f].v1-1].x, pVerts[pfaces[f].v1-1].y, pVerts[pfaces[f].v1-1].z);        glVertex3f(pVerts[pfaces[f].v2-1].x, pVerts[pfaces[f].v2-1].y, pVerts[pfaces[f].v2-1].z);        glVertex3f(pVerts[pfaces[f].v3-1].x, pVerts[pfaces[f].v3-1].y, pVerts[pfaces[f].v3-1].z);        glVertex3f(pVerts[pfaces[f].v4-1].x, pVerts[pfaces[f].v4-1].y, pVerts[pfaces[f].v4-1].z);    }    glEnd();}Face Face::operator = (const Face &param){    n1 = param.n1;    n2 = param.n2;    n3 = param.n3;    n4 = param.n4;    v1 = param.v1;    v2 = param.v2;    v3 = param.v3;    v4 = param.v4;    uv1 = param.uv1;    uv2 = param.uv2;    uv3 = param.uv3;    uv4 = param.uv4;    return *this;}


The code here is just enough so that i could load the model data into memory and render the verts onto the screen.
glBegin()/glEnd() is the slowest way you could be rendering this with opengl, look into vertexbuffer objects. The framerate doesnt have anything to do with the loader.
Quote:Original post by NumberXaero
glBegin()/glEnd() is the slowest way you could be rendering this with opengl, look into vertexbuffer objects. The framerate doesnt have anything to do with the loader.


I know that initial loading doesn't have much to do with the final framerate, but I figured I'd mention it since someone might know a better, more efficient way to get the data into memory.


If you need to improve loading speed, you can use a binary format, where you can just read the file bits directly into your memory array. This has the tradeoff of not being human editable or readable. If obj supports the features you need, you can export all of your models to obj, and then convert that into a binary format for your game to load.

[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
Quote:I know that initial loading doesn't have much to do with the final framerate
Well, you did title your thread 'framerate issues with my obj loader' :-)

Anyway, as NumberXaero said, that's about the slowest way you can render anything in OpenGL. VBOs will most likely give you much better results.
Quote:Original post by karwosts
You should definitely post code, I'm sure you can get some help here.

You're right that its not a terribly efficient format to load, but this should be a one time hit when program loads and shouldn't effect your framerate.

The methods you use to draw the data will matter a lot though. Are you by chance using immediate mode drawing (glBegin/glEnd)? This is a very slow method and should not be used, the proper method of drawing is to use Vertex Buffer Objects (VBO).

I'm sure we can give more specific advice once we see your rendering code.


I've been looking into this and I can't get it to work. could you show me how to implement this in the code i posted or show me a page that explains it?
Do you ever pass the objmodel object through a parameter?

For example you don't want to have a function called
int GetNumFaces(objmodel themodel);
I once did this and the copying of all that data every frame really took a toll. If this is your problem then just use a pointer.
int GetNumFaces(objmodel *themodel);

I don't see it in your code there but it still may be in your project.

This topic is closed to new replies.

Advertisement