OBJ Model Loading (In Detail)

Started by
15 comments, last by RobTheBloke 12 years, 8 months ago
Ranger,

Your source had a couple of bugs (DL version). And a couple a nit-picks of mine.
I cleaned up the code for improved readability. Changed a few naming conventions to std notation. Increased speed (very minor in the read / scan loops) (just make sure the file ends with a blank line!!!). Reduced code (with use of std lib's). I also added free to release the objects. Hope you don't take offence and rain on your parade.

main.cpp
#include <stdlib.h>#include <stdio.h>#include "obj.h"int main(){   char* memory = NULL;   size_t bytes = ObjLoadFile("tank.obj", &memory);   ObjModel* model = ObjLoadModel(memory, bytes);   printf("Object Model has: %d faces!\n", model->nTriangle);      free(model->NormalArray);   free(model->TexCoordArray);   free(model->TriangleArray);   free(model->VertexArray);   free(model);   system("PAUSE");      return 0;}


obj.cpp
#include <stdlib.h>#include <stdio.h>#include <memory.h>#include "obj.h"ObjModel* ObjLoadModel(char* memory, size_t size){	char* p = NULL, * e = NULL;   ObjModel* ret = (ObjModel*) calloc(1, sizeof(ObjModel));   memset(ret, 0, sizeof(ObjModel));	p = memory;	e = memory + size;		while (p != e)	{           if (memcmp(p, "vn", 2) == 0) ret->nNormal++;      else if (memcmp(p, "vt", 2) == 0) ret->nTexCoord++;      else if (memcmp(p, "v",  1) == 0) ret->nVertex++;      else if (memcmp(p, "f",  1) == 0) ret->nTriangle++;      while (*p++ != (char) 0x0A);   }   ret->VertexArray   = (ObjVertex*)   malloc(sizeof(ObjVertex) * ret->nVertex);   ret->NormalArray   = (ObjNormal*)   malloc(sizeof(ObjNormal) * ret->nNormal);   ret->TexCoordArray = (ObjTexCoord*) malloc(sizeof(ObjTexCoord) * ret->nTexCoord);   ret->TriangleArray = (ObjTriangle*) malloc(sizeof(ObjTriangle) * ret->nTriangle);	p = memory;	   int nV = 0, nN = 0, nT = 0, nF = 0;		while (p != e)	{      if (memcmp(p, "vn", 2) == 0)      {         sscanf(p, "vn %f %f %f", &ret->NormalArray[nN].x,                                  &ret->NormalArray[nN].y,                                  &ret->NormalArray[nN].z);         nN++;      }      else if (memcmp(p, "vt", 2) == 0)      {         sscanf(p, "vt %f %f", &ret->TexCoordArray[nT].u,                               &ret->TexCoordArray[nT].v);         nT++;      }      else if (memcmp(p, "v", 1) == 0) /* or *p == 'v' */      {         sscanf(p, "v %f %f %f", &ret->VertexArray[nV].x,                                 &ret->VertexArray[nV].y,                                 &ret->VertexArray[nV].z);         nV++;      }      else if (memcmp(p, "f", 1) == 0) /* or *p == 'f' */      {         sscanf(p, "f %d/%d/%d %d/%d/%d %d/%d/%d", &ret->TriangleArray[nF].Vertex[0],                                                   &ret->TriangleArray[nF].TexCoord[0],                                                   &ret->TriangleArray[nF].Normal[0],                                                   &ret->TriangleArray[nF].Vertex[1],                                                   &ret->TriangleArray[nF].TexCoord[1],                                                   &ret->TriangleArray[nF].Normal[1],                                                   &ret->TriangleArray[nF].Vertex[2],                                                   &ret->TriangleArray[nF].TexCoord[2],                                                   &ret->TriangleArray[nF].Normal[2]);         nF++;      }      while (*p++ != (char) 0x0A);   }        return ret;}size_t ObjLoadFile(char* szFileName, char** memory){	size_t bytes = 0;	FILE* file = fopen(szFileName, "rt");	if (file != NULL)   {	   fseek(file, 0, SEEK_END);	   size_t end = ftell(file);	   fseek(file, 0, SEEK_SET);   		   *memory = (char*) malloc(end);	   bytes = fread(*memory, sizeof(char), end, file);	   fclose(file);   }	return bytes;}


obj.h
#ifndef OBJ_H#define OBJ_Hstruct ObjVertex{   float x, y, z;};typedef ObjVertex ObjNormal;struct ObjTexCoord{   float u, v;};struct ObjTriangle{   int Vertex[3];   int Normal[3];   int TexCoord[3];};struct ObjModel{   int nVertex, nNormal, nTexCoord, nTriangle;   ObjVertex* VertexArray;   ObjNormal* NormalArray;   ObjTexCoord* TexCoordArray;   ObjTriangle* TriangleArray;};ObjModel* ObjLoadModel(char*, size_t);size_t    ObjLoadFile(char*, char**);#endif

Advertisement
Ok the C++ version of the code is complete...
sjf i haven't reviewed your code yet to see what improvements need to be made.

There are somethings i noticed about the obj format that i think we should include...

Support for faces that have more than 3 vertex/textureCoord/normal sets.
I modeled something in blender and it hade a few with like 6 f v/vt/vn data sets in a row.

Well here is the link to what I got.. it has been zipped for ease of downloading, i'll include the VC.NET Project files as well.

objLoaderTest.zip

and while i'm at it... how about you just look at my simple un updated webpage...
Justin Walsh's Homepage

thanks to all who help and have helped.

Now one last question...
How would you go about drawing all this shit in OpenGL?
can i just traingle strip it up from the first face in the array, to the last?
sjf,

I take no offense :) I did however write the code for clarity, and not for speed. I wanted to make sure you could see the process going on easily.

Justinrwalsh,

Yes, we need support for polygon faces. It would be quite simple to triangulate them, and we could use a couple different approaches to do so. Otherwise you could tell your modeller to triangulate the model before saving it (assuming that can be done). Groups are pretty useful too, and easy to add. All this would have made the code more unclear, and clarity was my prime objective.

Drawing the model is as simple as:

glBegin(GL_TRIANGLES);
... Iterate over faces, drawing each triangle.
glEnd()

Thanks! I appreciate the help.
*bump*
giant error in my source...

Uploading fixed code...

[Edited by - justinrwalsh on April 11, 2005 4:24:36 PM]
What's the license for this?
Holy crap I started a blog - http://unobvious.typepad.com/
How would you go about drawing all this shit in OpenGL?[/quote]

Step by step guide to obj files in C (Triangulates inputs meshes [in a simplistic way that can fail in some cases] with VertexArray and TBN generation). Starts simple, gets very complicated towards the end. All of this written in the days before shaders though, so the Dot3 example may want converting to GLSL instead,
http://nccastaff.bou...e/ObjLoader.zip

basic C++ library (with beziers, materials, groups and lots of other stuff)
http://nccastaff.bou.../www/libObj.zip

\edit.
Wow. That's a very old thread you dug up there ;)

This topic is closed to new replies.

Advertisement