Sign in to follow this  

OBJ Import problems

This topic is 4382 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

hi, I have been trying to write a 3D asteroid hunting space simulation, however I have serious problems with importing my spaceship. I have modeled it with Maya and exported it with polytrans plug-in. I have tried open-source obj import libraries but my ship looked a little bit deformed once I displayed it. Then I have written my importer code, and for simplicity I have only written code for importing vertices, faces and vertex normals. But it again displayed deformed, as if some faces are defined wrong. But I don't think my library or open-source library I have used have problems, and also I don't think Maya and the plug-in have problems with exporting the obj file. Does anyone know where the problem should be? is there a process that I should do after exporting the file? btw, here is my simple obj importer code:
[/source
int LoadObjFileToClass(char* filename, object* ObjClass) {

	std::ifstream ObjFile(filename);

	if(!ObjFile.is_open())
		return NULL;
			
			//yuzey, vertex vs. sayilarini say
	std::string line, sub;	//bir satir maksimum 80 karakter
	int numVertex = 0, numFace = 0, numNormal = 0;
	while(getline(ObjFile, line)) {
		
		sub = line.substr(0,2);
		if(sub == "v ")
			numVertex++;
		else if(sub == "f ")
			numFace++;
		else if(sub == "vn")
			numNormal++;
	}
			//gerekli yerleri tahsis et atamalari yap
	ObjClass->LocalVertices = new Vertex3D[numVertex];
	ObjClass->Faces			= new Facet[numFace];
	ObjClass->Normals		= new Normal[numNormal];

	ObjClass->NumVertices	= numVertex;
	ObjClass->NumFaces		= numFace;
	ObjClass->NumNormals	= numNormal;

 	ObjFile.close();

	std::ifstream ObjFile2(filename);
	
	int vertex = 0, face = 0, normal = 0;
	int vi1, vi2, vi3, ni1, ni2, ni3, vt1, vt2, vt3;
	float x, y, z;

	while(getline(ObjFile2, line)) {
		const char* FormattedLine = line.c_str();
		sub = line.substr(0,2);
		std::string empty;

		if(sub == "v ") {
			//string vertex tanimliyor
			sscanf(FormattedLine, "%s %f %f %f", ∅, &x, &y, &z);
			ObjClass->LocalVertices[vertex].x = x;
			ObjClass->LocalVertices[vertex].y = y;
			ObjClass->LocalVertices[vertex].z = z;
			vertex++;
		}
		else if(sub == "f ") {
            sscanf(FormattedLine, "%s %d/%d/%d %d/%d/%d %d/%d/%d", ∅, 
				&vi1, &vt1, &ni1, 
					&vi2, &vt2, &ni2, 
						&vi3, &vt3, &ni3);
			ObjClass->Faces[face].VertexIndices[0] = vi1;
			ObjClass->Faces[face].VertexIndices[1] = vi2;
			ObjClass->Faces[face].VertexIndices[2] = vi3;

			ObjClass->Faces[face].Normals[0] = ni1;
			ObjClass->Faces[face].Normals[1] = ni2;
			ObjClass->Faces[face].Normals[2] = ni3;
			face++;
		}
		else if(sub == "vn") {
			sscanf(FormattedLine, "%s %f %f %f", ∅, &x, &y, &z);
			ObjClass->LocalVertices[vertex].x = x;
			ObjClass->LocalVertices[vertex].y = y;
			ObjClass->LocalVertices[vertex].z = z;
			normal++;
		}
	}

	return true;

}]


Share this post


Link to post
Share on other sites
Are any of the face indices negative? A positive value indexes from the beginning of the vertex list. A negative value indexes from the end of the list. I don't see any check in your import code for negative indices.

Share this post


Link to post
Share on other sites
.obj files use indices that are 1-based instead of 0-based, so you have to subtract 1 when you build your lists.

Twice I've written an obj importer, and twice I've had that same bug. Looks like it could be your problem also.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Dave Hunt, you are sure about the negative indexes? I never saw such a .obj file

Patroclos, what does "∅" in sscanf means? I have no idea what this should do
sscanf(FormattedLine, "%s %f %f %f", ∅, &x, &y, &z);

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
do you want to use "std::string empty;" in the sscanf calls for the first "%s"?
this does not work, you must use a "char empty[YOUR_MAX_SIZE_FOR_THIS];"

Share this post


Link to post
Share on other sites
Dave I ckecked my obj file but there doesn't seem to be any negative indices.
I think the odd character in sscanf occured while copying code into forum. Because there is no such a character in the source code.
while checking obj file I think I have found a bug. There are 4-5 faces that are defined by 18 vertices. but I have triangulated all polygons in maya and I have used only quads to model the ship. this seems to be strange problem

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Dave Hunt, you are sure about the negative indexes? I never saw such a .obj file


Yep. Check the OBJ Format. Look at the section headed "Referencing vertex data".

Also, ajas95 has made a significant point - the indices are 1-based, not 0-based. So, all your indices are going to be off by one unless you subtract 1 from each index.

Share this post


Link to post
Share on other sites
I think most errors occur when people make assumptions about spacing and formatting.

I see you are making an assumption that every "f" line is formatted in some certain way, and that's not correct.
Index parameters on that line can be optional, and you're assuming every face is a triangle, which is wrong too.
I think you need another way other than "sscanf" to process a "f" line. Need to step through it, token by token.

[Edited by - JakeM on December 18, 2005 8:31:32 PM]

Share this post


Link to post
Share on other sites
I have triangulated all polygons in Maya.. That's why I written code for only reading triangles. However I thought I have turned all polygons into triangles, but I have missed some polygons as I see.. I think it happened because I didn't make triangulation in object mode.. anyway I have solved the problem, now I can draw the ship however there is still a small problem. The details of the ship are lost, I mean there were some spacings on the ship but they are all filled.. as if there has been a big data loss during conversion from double to float.

By the way, JakeM you're right but I just wanted to write a specific obj loader. I mean I just wanted to use it in that game not in general that's why I don't make so many format checkings. Actually I wanted to use open-source libraries for importing but when I encountered problems I decided to write my own importer..

Share this post


Link to post
Share on other sites
Heres my code for importing OBJs exported from Maya, it will handle most OBJ formatting

bool TGeoForm::LoadOBJFile(AnsiString filename, mesh *msh, float scale)
{
FILE *fp = fopen(filename.c_str(), "rt");

if(fp == NULL)
return(false);

int i;

try
{
char s[2049];

msh->DeleteAll();

point *pt;
polygon *poly;

bool hasuvs = false, hasnormals = false, haspts = false;
int ccount = 0;
bool namefound = false;

while(fgets(s, 2048, fp) != NULL)
{
if(toupper(s[0]) == 'G')
{
//if(namefound)
// return(false);
namefound = true;
}
else if(toupper(s[0]) == 'V')
{
if(toupper(s[1]) == 'N')
{
pt = new point;

if(sizeof(GEOFLOAT) == 4)
sscanf(&s[3], "%f %f %f", &pt->x, &pt->y, &pt->z);
else
sscanf(&s[3], "%lf %lf %lf", &pt->x, &pt->y, &pt->z);
pt->w = 0.0f;
msh->AddNormal(pt);


hasnormals = true;
}
else if(toupper(s[1]) == 'T')
{
pt = new point;

if(sizeof(GEOFLOAT) == 4)
sscanf(&s[3], "%f %f", &pt->x, &pt->y);
else
sscanf(&s[3], "%lf %lf", &pt->x, &pt->y);
pt->z = pt->w = 0.0f;
msh->AddUV(pt);

hasuvs = true;
}
else
{
pt = new point;

if(sizeof(GEOFLOAT) == 4)
sscanf(&s[2], "%f %f %f", &pt->x, &pt->y, &pt->z);
else
sscanf(&s[2], "%lf %lf %lf", &pt->x, &pt->y, &pt->z);

pt->w = 0.0f;

*pt *= scale;

msh->AddPoint(pt);

haspts = true;
}
}
else if(toupper(s[0]) == 'F')
{
poly = new polygon;
char *ps = &s[2];
char num[256], *pnum;

poly->sides = 0;
for(i=0; i<4; i++)
{
poly->points[i] = poly->normals[i] = poly->uvs[i] = -1;
}

bool done = false;
int val;

while(!done)
{
while(*ps == ' ')
ps ++;

// points
pnum = num;
*pnum = 0;
while((*ps != '/' && *ps != ' ') && !done)
{
*pnum = *ps;
pnum ++; ps ++;
if(*ps == 0)
done = true;
}
*pnum = 0;
if(sscanf(num, "%d", &val) == 1)
{
if(val < 0)
poly->points[poly->sides] = msh->NormalCount()+val;
else
poly->points[poly->sides] = val - 1;
}

if(*ps != ' ')
{
ps ++;

// uv
pnum = num;
*pnum = 0;
while((*ps != '/' && *ps != ' ') && !done)
{
*pnum = *ps;
pnum ++; ps ++;
if(*ps == 0)
done = true;
}
*pnum = 0;
if(sscanf(num, "%d", &val) == 1)
{
if(hasuvs)
{
if(val < 0)
poly->uvs[poly->sides] = msh->UVCount()+val;
else
poly->uvs[poly->sides] = val - 1;
}
else if(hasnormals)
{
if(val < 0)
poly->normals[poly->sides] = msh->NormalCount()+val;
else
poly->normals[poly->sides] = val - 1;
}
else
{
ShowMessage("More cv indicies than data types in obj (there are no normals "
"or uvs but there are poly indicies for them)");
return(false);
}
}

if(*ps != ' ')
{
ps ++;

// normal
pnum = num;
*pnum = 0;
while((*ps != '/' && *ps != ' ') && !done)
{
*pnum = *ps;
pnum ++; ps ++;
if(*ps == 0)
done = true;
}
*pnum = 0;

if(sscanf(num, "%d", &val) == 1)
{
if(val < 0)
poly->normals[poly->sides] = msh->NormalCount()+val;
else
poly->normals[poly->sides] = val - 1;
}
}
}
poly->sides ++;
if(poly->sides>4)
{
ShowMessage("Object contains polygons with more than 4 sides! Ouch..");
return(false);
}
}
msh->AddPolygon(poly);
}
}
}
__finally
{
fclose(fp);
}
return(true);
}

Share this post


Link to post
Share on other sites
code i use to read the face 'f' flags and triangulate the polygons on input (it assumes that 'f' has been read from the file). Yes it uses goto, but it works so there :p



//---------------------------------------------------------------------- File :: ReadFace
void File::ReadFace(std::istream& ifs) {
char c;
std::vector<std::string> VertInfo;

// store all strings
do {
// strip white spaces
c = ifs.get();
if (ifs.eof()) {
goto vinf;
}
while(c==' ' || c=='\t') {
c=ifs.get();
if (ifs.eof()) {
goto vinf;
}
}
std::string s;

// read vertex info
while(c!=' '&&c!='\t'&&c!='\n') {
s+=c;
c=ifs.get();
if (ifs.eof()) {
goto vinf;
}
}

// store string
VertInfo.push_back(s);
}
while(c!='\n'); // loop till end of line

vinf: ;
std::vector<int> verts;
std::vector<int> norms;
std::vector<int> uvs;
// split strings into individual indices
std::vector<std::string>::const_iterator it = VertInfo.begin();
for( ; it != VertInfo.end(); ++it ) {
int v, n=0, t=0;

if(HasOnlyVertex(*it))
sscanf(it->c_str(),"%d",&v);
else
if(MissingUv(*it))
sscanf(it->c_str(),"%d//%d",&v,&n);
else
if(MissingNormal(*it))
sscanf(it->c_str(),"%d/%d/",&v,&t);
else
sscanf(it->c_str(),"%d/%d/%d",&v,&t,&n);

if (v<0) {
v=static_cast<int>(m_Vertices.size())+v+1;
}
if (n<0) {
n=static_cast<int>(m_Normals.size())+n+1;
}
if (t<0) {
t=static_cast<int>(m_TexCoords.size())+t+1;
}

// obj indices are 1 based, change them to zero based indices
--v; --n; --t;

verts.push_back(v);
norms.push_back(n);
uvs.push_back(t);
}

// construct triangles from indices
for(unsigned i=2;i<verts.size();++i) {
Face f;

// construct triangle
f.v[0] = verts[0];
f.n[0] = norms[0];
f.t[0] = uvs[0];
f.v[1] = verts[i-1];
f.n[1] = norms[i-1];
f.t[1] = uvs[i-1];
f.v[2] = verts[i];
f.n[2] = norms[i];
f.t[2] = uvs[i];

// append to list
m_Triangles.push_back(f);
}
}



Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Dave Hunt, you are sure about the negative indexes? I never saw such a .obj file

Patroclos, what does "∅" in sscanf means? I have no idea what this should do
sscanf(FormattedLine, "%s %f %f %f", ∅, &x, &y, &z);


yes, the obj file supports negative indices. if it uses positive indices, then the vertex reference is relative to the start of the file (maya only does +ve). If it is a negative index it is relative to it's current position (not as posted before, from the end of the list). ie, -1 indicates the last vertex read.

Share this post


Link to post
Share on other sites
Quote:
Original post by RobTheBloke
If it is a negative index it is relative to it's current position (not as posted before, from the end of the list). ie, -1 indicates the last vertex read.


That's actually what I meant - the end of the list at the time the negative reference is made. But you're right. My statement was misleading.

Share this post


Link to post
Share on other sites
Quote:
Original post by ajas95
.obj files use indices that are 1-based instead of 0-based, so you have to subtract 1 when you build your lists.

Twice I've written an obj importer, and twice I've had that same bug. Looks like it could be your problem also.


ajas95 you were right :) I have subtracted 1 from each index and it drew the ship correctly.. thanks very much too all for help

Share this post


Link to post
Share on other sites

This topic is 4382 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