Sign in to follow this  

framerate issues with my obj loader

This topic is 2785 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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 ¶m);
};

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[i] == ' ')
{
c++;
}
else
{
vString[c].push_back(line[i]);
}
}

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[i] == ' ')
{
c++;
}
else
{
vString[c].push_back(line[i]);
}
}

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[i] == ' ')
{
c++;
}
else
{
vString[c].push_back(line[i]);
}
}


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[i] == ' ')
{
c++;
}
else
{
fString[c].push_back(line[i]);
}
}

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 ¶m)
{
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites


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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

This topic is 2785 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this