My .obj file loader

kberg
Unregistered
 
Post: #1
One of the big problems I faced when creating my game engine was what to use for a 3D model format. I couldn't find any decent libraries that provided model loading functionality, and the amount of Mac friendly example code out there is pretty small.

It took me a long time to figure out which format to implement, and even longer to implement it. I eventually decided on using .obj's since they are realtively simple to parse, and have all the features that I needed.

To save anyone else the grief I went through, I've decided to give away my .obj class as thanks for all the help I've received from communities like this. The code is totally free; though if you see any obvious problems, or make any really cool enhancements, I wouldn't mind getting a modified copy back Grin

The model files are simply ModelType.cpp, and ModelType.h. I've thrown in my tga loaders for completeness, though those functions normally don't live there. To load a model is simple: LoadObj(char* filename, char* texturename, float scale, int normal type). To draw a model once it has been loaded is simply Draw(), and to clean up, call Delete() when you quit your app.

filename and texturename are regular c character arrays, scale is a float that will resize the model at load time without mucking up any of the normals. Normal type is only used when the obj file does not provide normals. 0 will generate face normals (faceted appearance), and 1 will generate vertex normals (smooth appearance).

This obj loader supports the following features: mixed triangle and quad meshes (less then 3 or more then 4 vertices in a face will cause probs), normals, uv and uvw texture coordinates. It doesn't have support for .mtl files, smoothing groups, or multiple objects within a single object (they are all loaded as a single object).

To demo the class, I've hacked up a Nehe tutorial Rasp

http://www.sfu.ca/~kberg/ObjExample.tgz

Hope someone finds this useful.
Quote this message in a reply
AJ Infinity
Unregistered
 
Post: #2
Definitely me. If your classes are what I think they are (I have looked at them yet), then I'm very grateful. Hey, maybe I'll give you my animation class. Grin (when it's finished)

It'll make OBJ loading simpler for me.
Quote this message in a reply
bombinator
Unregistered
 
Post: #3
Of course I would start writing a loader last night. Of course I would finish it at 4 in the morning. And of course someone would release a loader today. LOL *Sigh* Oh well, my loader still chokes on some files. I figured out what is going wrong this afternoon but whether or not I fix it now probably hinges on whether or not I download your loader.

Todd Chaffins
Quote this message in a reply
Founder
Posts: 1,138
Joined: 2002.04
Post: #4
Hi,

You might want to @ackage this up (for example, add license, etc) and send it to our Source Code Editor (Johan) so he can place it on iDevGames so people can find it down the road.

Cheers

Carlos A. Camacho,
Founder
iDevGames
Quote this message in a reply
kberg
Unregistered
 
Post: #5
I've posted a modified version to the same address which includes a read-me and my licensing terms (none). Is there anything else that I should add to this? Or should I just email Johan with all of this?

The address again is http://www.sfu.ca/~kaberg/Downloads/ObjExample.tgz
Quote this message in a reply
Apprentice
Posts: 5
Joined: 2009.01
Post: #6
Is there anything else that I should add to this? Or should I just email Johan with all of this?

No need to. I got it.

Cheers,
Johan
Quote this message in a reply
honkFactory
Unregistered
 
Post: #7
There are several errors in this .obj loader. I have contacted kberg about these, and I am sure that he will address them in a timely manner. Until then I recommend you hold off using this class. I have decided to use this class, only with a more effficient memory handling setup. Since I think it is important that I understand the setup of the class before I start screwing around with memory allocation I have undertaken proof reading and correcting these error. If the kberg does not correct them you can contact me and I can give you my version.

Also, I need a .obj model that has both triangles and quads so I can adequately test this class. The .obj fighter plane model that comes with the class is triangles only. (Many of the errors in the current version are in the quad handling.) If anyone out there could make me a sample .obj model so I could test this class I would be grateful. It doesn't have to be fancy; a spheroid will do. I would do it myself but I do not have a modeling program.

Thanks
AW
Quote this message in a reply
ghettotek
Unregistered
 
Post: #8
did anyone happen to port this to Obj-C? im having a hell of a time doing it for some reason.
Quote this message in a reply
honkFactory
Unregistered
 
Post: #9
Howdy, I found a .obj model with mixed triangl and quad surfaces. However I found something in the .obj file that I have not found in any documentation, specifically the lines

f 1488/838/4134 1489/840/4135 1490/839/4136 1475/825/4137\
1474/824/4138

I think that the \ character just signifies that the current line is a continued on the next. This loader does not handle this. Also in this file there are faces, like the one above, that have 5 vertices. I thought that .obj models were just supposed to be 3 or 4 sided, but i guess I am wrong. Am I? My instinct would be to triangulate these surfaces, which would avoid rendering problems if the vertices are not planar. Or at least triangulate them when building the display list.

Alex
Quote this message in a reply
kberg
Unregistered
 
Post: #10
Quote:Originally posted by honkFactory
Howdy, I found a .obj model with mixed triangl and quad surfaces. However I found something in the .obj file that I have not found in any documentation, specifically the lines

f 1488/838/4134 1489/840/4135 1490/839/4136 1475/825/4137\
1474/824/4138

I think that the \ character just signifies that the current line is a continued on the next. This loader does not handle this. Also in this file there are faces, like the one above, that have 5 vertices. I thought that .obj models were just supposed to be 3 or 4 sided, but i guess I am wrong. Am I? My instinct would be to triangulate these surfaces, which would avoid rendering problems if the vertices are not planar. Or at least triangulate them when building the display list.

Alex


You are correct in this assumption. Certain modellers (lightwave for one) are capable of outputting polygons with greater then 4 vertices when generating a .obj file, and in this case the forward slash certainly does look like a line break. I have not encountered this in any .obj file I have looked at yet though. I have not bothered to add support for > 4 sided polygons as my 3D guy uses 3D studio, which only outputs triangulated .obj meshes.

I have looked over all the errors you have brought to my attention, and have corrected them. I will be contacting Johan shortly to replace the older version with this corrected one. Thanks for the feedback! I'm pretty sure that this has saved me a lot of headaches in future.
Quote this message in a reply
honkFactory
Unregistered
 
Post: #11
This would make a good Obj-C class. Since most of the computation in this class would be done while setting up for animation and not during animation I don't think there would be much worry about Obj-C being to slow. I have become wary of using Obj-C after I used a combo of NSArray and NSDictionary for my data structures in a test game with negative (slow) results.
I hadn't thought to port it because I already have decided to use some a C++ based collision detection library in my game so adding another C++ class to the project is no inconvenience for me. I would guess that kberg would probably not be interested seeing as he modified a Carbon port of a NeHe tutorial rather than a Cocoa port and he prefered to write in C++ in the first place. If I can get modivated I might do it myself.

AW
Quote this message in a reply
kberg
Unregistered
 
Post: #12
I have temporarily posted the corrected version on my website:

http://www.sfu.ca/~kberg/ObjLoader.tgz

I have also emailed Johan regarding this corrected version, so he can swap it for the old one currently in the source code download section.

I currently have no experience with Obj-C, and so would probably horribly botch any such conversion myself...
Quote this message in a reply
Moderator
Posts: 133
Joined: 2008.05
Post: #13
One of the errors I've encountered using this, is loading .obj files from applications such as Lightwave Modeler and Poser in Mach-O(It was working in a Carbon Toolbox though). It works fine on Bryce5 files. When I looked at it in my debugger, the ReadLines function will grab more than one line. So it reads something like: "v 0.4 0.2 0.1\rv 0.2 0.4 0.01\r" and it keeps going on. So therefore it would only read every 5 lines or something, and eventually just mess it up altogether.

An easy fix I found was just to create another fgets function.
char * _MSL_CDECL better_fgets(char * s, int n, FILE * file)
{
char * p = s;
int c;

if (--n < 0)
return(NULL);
__begin_critical_region(files_access);

if (n)
do
{
c = getc(file);

if (c == EOF)
if (file->state.eof && p != s)
break;
else
{
__end_critical_region(files_access);
return(NULL);
}

*p++ = c;

}
while ( c != '\n' && c!='\r' && --n);
__end_critical_region(files_access);

*p = 0;

return(s);
}

The only change is in the while clause, you just add a c!='\r', and it will read the line correctly on those files. Plus it reads the other files fine too.
Quote this message in a reply
kberg
Unregistered
 
Post: #14
Wow, yeah that's a good way to handle the different line breaks. I had been opening up any offending files in Project Builder and changing the line endings to 'Unix' line endings (under the format menu).

Thanks for providing the code, I'll definately integrate that into my version and post it for others to download if they want.Grin
Quote this message in a reply
kberg
Unregistered
 
Post: #15
I must show some ignorance here ( Blush ), and ask for help with the __begin_critical_region() and __end_critical_region() macros. I'm guessing that they prevent the thread from being swapped out in a MT environment? and that this is used to ensure the state of file doesn't change. I couldn't find any mention of this either on the web, or by text-content searching my developer folder though.

Also, I can't find any info on the _MSL_CDECL function attribute; the closest thing I could find was this blurb:
Quote:cdecl
On the Intel 386, the cdecl attribute causes the compiler to assume that the calling function will pop off the stack space used to pass arguments. This is useful to override the effects of the -mrtd switch.

The PowerPC compiler for Windows NT currently ignores the cdecl attribute.
..from the GCC 3 documentation.

Otherwise your code works perfectly for me! Grin
Once I make sure that the following is ok, or work out the above issues, I will post a new loader example for others to download.

Code:
//Code provided by LongJumper of the iDevGames forums
char* better_fgets(char* s, int n, FILE* file)
{
    char*    p = s;
    int        c;
        
    if (--n < 0)
        return(NULL);                

    if (n)
    {
        do
        {
            c = getc(file);

            if (c == EOF)
            {
                if (feof(file) && p != s)
                    break;
                else
                {              
                    return(NULL);
                }
            }
            *p++ = c;
        }
        while (c != '\n' && c!='\r' && --n);
    }                                              
    *p = 0;

    return(s);
}
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Display Lists and Obj. File Loader Problems merrill541 0 1,968 Oct 17, 2008 06:42 PM
Last Post: merrill541