Need advice on my first obj file loader (just saying that Im a noob.. TQ)

Started by
15 comments, last by ernow 13 years, 10 months ago
Hi All,

I'm a newcomer in 3D programming.
Currently, i'm working on a project to load an OBJ file using CsGL wrapper for OpenGL in C#. I realized that my obj loader cannot read an obj file if the 'f v/vn/vt...' commands isn't put at the end of the file (for example, if the content of the obj file is like the following, the loader runs just fine.

v 1 1 1
v 1 1 -1
v 1 -1 1
v 1 -1 -1
v -1 1 1
v -1 1 -1
v -1 -1 1
v -1 -1 -1
f 1 3 4 2
f 1 5 6 2
f 1 5 6 2
f 3 7 8 4
f 1 5 7 3
f 2 6 8 4

however, if the 'f ...' commands relocated somewhere in the middle of the obj file, like the following,

v 1 1 1
v 1 1 -1
v 1 -1 1
v 1 -1 -1
f 1 3 4 2
f 1 5 6 2
f 1 5 6 2
f 3 7 8 4
f 1 5 7 3
f 2 6 8 4
v -1 1 1
v -1 1 -1
v -1 -1 1
v -1 -1 -1

the loader will crash. (i knew what caused it, and planning to make the loader reads the obj file twice -- 1st read -> collect vertices informations, 2nd read -> collect faces information. however, i think it will cause performance problem.

will someone take a look at my code (in the following link) and give suggestions on improving it?

http://hotfile.com/dl/52025645/661417e/first_obj_loader.still.contain.bug.zip.html

thank you in advance.
Advertisement
Quote:Original post by silentcoder89
planning to make the loader reads the obj file twice -- 1st read -> collect vertices informations, 2nd read -> collect faces information. however, i think it will cause performance problem.
Why in two passes? You could just collect both vertex and face data in one pass through the file, close it and then work on assembling the mesh from the face indices afterwards.
Quote:Original post by dmatter
Why in two passes? You could just collect both vertex and face data in one pass through the file, close it and then work on assembling the mesh from the face indices afterwards.

Because, in my loader, i stored the vertices in an arrayList, then created the faces "on-the-fly" while reading the 'f..' command. as we know, the f command in obj file is in this syntax - f v1/vn1/vt1, which v or vn or vt is the index of vertices which are required to construct the face. However, what if the vertices that certain 'f..' command refers isn't yet loaded into the array? say -

[vertex index:100] v 1 1 1 1
f 100 101 102
[vertex index:101] v 1 0 1 -1
[vertex index:102] v 1 0 0 0

what about the above? according to the 'f..' command, it takes the vertices from index 100, 101, and 102. Maybe the 100th vertex will do, but i don't think the 101st n 102nd will be available to be referred. Because, it doesn't yet loaded into the array.

Or did we should load all the information first (into the array) then construct it? My approach is -- construct on the fly. (inside the file reading loop)
Thanks for your help.


Quote:Original post by silentcoder89
However, what if the vertices that certain 'f..' command refers isn't yet loaded into the array?
A well-formed obj file wouldn't do that to you, faces should only reference backwards into the file. That said, it's always a good idea to code defensively and it'd be a more robust loader if you can handle this case.

Quote:Or did we should load all the information first (into the array) then construct it? My approach is -- construct on the fly. (inside the file reading loop)
Yes. It is easier to simply load all infos in first and then construct the mesh. It's also certainly better than scanning through the file twice.
i see. But, won't it be 'time-taking'? I got your point. I'll implement that right away. Meanwhile, is it ideal to use ArrayList to store the vertices and faces information? Im seeking a better way. And i'm trying to use the traditional array. But it wasn't dynamic. So, it will be a bit hard to implement.
Side question: is there that much flexibility in the .obj file type that different exporters can inject face data in the middle of a vert list? I've only really used Blender to create .obj files, so I may be uninformed here, but I always had face lists after all vert data was written.

When I wrote my .obj loader for a Java library, I just maintained a list of Face objects that stored their verts (edit: well, the vert's index), and as I read in individual v lines I appended to an Arraylist (vector). That way no matter what order you read in the data, the faces should refer to valid array indexes when you go to render polygons.

Hazard Pay :: FPS/RTS in SharpDX (gathering dust, retained for... historical purposes)
DeviantArt :: Because right-brain needs love too (also pretty neglected these days)

Here's a partial rewrite of your code to make it shorter. Completely untested.

void LoadObj(string filename){    try    {        using (StreamReader sr = new StreamReader(filename, System.Text.ASCIIEncoding.ASCII))        {            string line;            while ((line = sr.ReadLine()) != null)            {                line = line.Trim();                if (line.Length == 0 || line.StartsWith("#")) continue;                if (line[0] == 'v')                {                    ParseVertex(line);                }                else if (line[0] == 'f')                {                    //...                }            }        }    }    catch (Exception e)    {        //...    }}void ParseVertex(string line){    string[] cLine = line.Split(' ');    float a = float.Parse(cLine[1]);    float b = float.Parse(cLine[2]);    float c = cLine.Length <= 3 ? 0.0f : float.Parse(cLine[3]);    switch (line[1])    {        case 't':            VTexture.Add(new VertexTexture(a, b, c));            break;        case 'n':            VNormal.Add(new VertexNormal(a, b, c));            break;        default:            Vertices.Add(new Vertex(a, b, c));            break;    }}


Also, you should use List<> instead of ArrayList:

List<Vertex> Vertices = new List<Vertex>();List<VertexTexture> VTexture = new List<VertexTexture>();List<VertexNormal> VNormal = new List<VertexNormal>();List<Face> Faces = new List<Face>();
Side question: is there that much flexibility in the .obj file type that different exporters can inject face data in the middle of a vert list?
I'm not sure. But most of them puts the face commands at the end of the file. Try to take a look at one of the model in this site http://www.oyonale.com/modeles.php?lang=en&format=OBJ, i can't load most of it's obj file.

Also, you should use List<> instead of ArrayList:

List<Vertex> Vertices = new List<Vertex>();List<VertexTexture> VTexture = new List<VertexTexture>();List<VertexNormal> VNormal = new List<VertexNormal>();List<Face> Faces = new List<Face>();



Actually i'm not so familiar with it. Would you care to explain?
According to MSDN (I was curious) the List<> collection is the generic equivalent of the ArrayList, and in most cases performs better. It still grants you the ability to search by index like an ArrayList would.

Hazard Pay :: FPS/RTS in SharpDX (gathering dust, retained for... historical purposes)
DeviantArt :: Because right-brain needs love too (also pretty neglected these days)

This topic is closed to new replies.

Advertisement