Feedback on drawing method

Member
Posts: 24
Joined: 2008.02
Post: #1
Hello everybody!

I just wanted to get some feedback on how I am doing my drawing of an object.

I have just finished writing a basic .obj model loader using NSScanner. I wanted to know if the way I am displaying the model is good, or if there is a better way of doing it.

After I have loaded my object, all the data is in three C arrays: vertices[][], textureVertices[][], and faces[][][]. The first two arrays contain the actual data, while the third tells me what to draw when the time comes.

Here is the display method. Hopefully this will explain why I did what I did in loading the model.

Code:
for (i = 0; i < numberOfFaces; i++) {
    glBindTexture(GL_TEXTURE_2D, tex[0]);
    glBegin(GL_POLYGON);
        
    for (j = 0; j < 4; j++) {
        glTexCoord2f(textureVertices[faces[i][j][1]-1][0], textureVertices[faces[i][j][1]-1][1]); glVertex3f(vertices[faces[i][j][0]-1][0], vertices[faces[i][j][0]-1][1], vertices[faces[i][j][0]-1][2]);
    }
    glEnd();
    }

The "i" tells me what face were drawing, while the "j" tells me what point were drawing. I specify 0 to get vertex data, and a 1 to get texture data.The question: Is this an okay way of drawing an object? Are there better ways of drawing the data you get when you parse an .obj file? Thanks for any feedback.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #2
It looks like you're submitting 4 vertices per primitive. I've never used GL_POLYGON before but this looks like a good situation to be using GL_QUADS.

Also, if I were you I'd calculate surface normals and submit them or else your lighting will look wonky ( or simply will not work at all ).
Quote this message in a reply
Member
Posts: 24
Joined: 2008.02
Post: #3
Thanks for the reply! I don't have the normals parsed yet, but once I do, I'll pass them through. As to the GL_POLYGON, I had wanted to be able to draw faces with more than 4 points, but I didn't have a way to find out how many points per face yet, so I threw in the static 4 for testing. But your right, GL_QUADS works fine as well. I am not an OpenGL expert at all, which is why I need feedback on this kind of stuff.
Quote this message in a reply
Member
Posts: 283
Joined: 2006.05
Post: #4
Man With No Name Wrote:I have just finished writing a basic .obj model loader using NSScanner.

Hey, me too!

Do you simply not support triangles? I found the best way (for performance, not for ease of writing) was to make an array of quads and an array of triangles. Then I only had to do one glBegin/glEnd for all the triangles and another for all the quads.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #5
I just decomposed my quads into triangles. I'm not saying that's the best way, but it made it easiest for me to handle normals and shadow-volume extrusion. Also, when I model in Wings3D I just make certain that everything's triangulated, anyway. This way I don't have to worry about N-gons.

My .obj parser was written in one morning using vanilla C++ and some of my own string tokenizing code. NSScanner frightens me a little.
Quote this message in a reply
Member
Posts: 24
Joined: 2008.02
Post: #6
Yeah, NSScanner is sort of difficult to debug because if there is a mistake, it just freezes the app with no explanation. But I don't like to program in C++ if I can avoid it. Tastes like charcoal.

maximile, could you explain a little more about what you do with the array of quads and triangles? Do you determine what's a triangle and what's a quad, then store them appropriately? It sounds interesting.
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #7
I used NSScanner without any problems. GL_POLYGON was the route I tried first as well. Turns out GL_POLYGON is a waste of time, since nobody who outputs obj files containing faces of more than four sides bothers to make them convex. To deal with obj files that contain complex faces (more than a quad, non-convex, self-intersecting, etc.) you will have to tessellate them -- either yourself, which is near impossible, or with glu tessellation routines, which is much easier, but quite hard to figure out how to do at first since the documentation available for it either completely sucks, or is plain incorrect (not to mention I think the implementation on the Mac isn't to spec with the tess callbacks, which throws yet another wrench in the works).

I know that the obj spec says that faces are supposed to be convex and neat and everything, but that simply is not what you'll find in the wild. You will wind up either having to tessellate and clean up the polys yourself, as I mentioned above, OR not accept anything more than quads, and pre-process the obj files to be triangulated in an external program like Wings3D, as TommorrowPlusX does. Being as how I've successfully written a robust obj loader myself, I can say that not allowing complex faces would make the work of writing a solid obj loader at least an order of magnitude easier. Wink
Quote this message in a reply
Member
Posts: 283
Joined: 2006.05
Post: #8
Yeah, I just have two arrays when I'm reading the obj file, one for quads and one for triangles. Then my drawing code looks like this (where group is an NSDictionary created from the obj file):

Code:
facesEnumerator = [[group objectForKey:@"quads"] objectEnumerator];
glBegin(GL_QUADS);
    while (face=[facesEnumerator nextObject]) {
        pointsEnumerator = [face objectEnumerator];
        while (point=[pointsEnumerator nextObject]) {
            glTexCoord2d([[[point valueForKey:@"tex"] valueForKey:@"x"] floatValue],[[[point valueForKey:@"tex"] valueForKey:@"y"] floatValue]);
            glNormal3f([[[point valueForKey:@"norm"] valueForKey:@"x"] floatValue],[[[point valueForKey:@"norm"] valueForKey:@"y"] floatValue],[[[point valueForKey:@"norm"] valueForKey:@"z"] floatValue]);
            glVertex3f([[[point valueForKey:@"vert"] valueForKey:@"x"] floatValue],[[[point valueForKey:@"vert"] valueForKey:@"y"] floatValue],[[[point valueForKey:@"vert"] valueForKey:@"z"] floatValue]);
        }
    }  
glEnd();

facesEnumerator = [[group objectForKey:@"triangles"] objectEnumerator];
glBegin(GL_TRIANGLES);
    while (face=[facesEnumerator nextObject]) {
        pointsEnumerator = [face objectEnumerator];
        while (point=[pointsEnumerator nextObject]) {
            glTexCoord2d([[[point valueForKey:@"tex"] valueForKey:@"x"] floatValue],[[[point valueForKey:@"tex"] valueForKey:@"y"] floatValue]);
            glNormal3f([[[point valueForKey:@"norm"] valueForKey:@"x"] floatValue],[[[point valueForKey:@"norm"] valueForKey:@"y"] floatValue],[[[point valueForKey:@"norm"] valueForKey:@"z"] floatValue]);
            glVertex3f([[[point valueForKey:@"vert"] valueForKey:@"x"] floatValue],[[[point valueForKey:@"vert"] valueForKey:@"y"] floatValue],[[[point valueForKey:@"vert"] valueForKey:@"z"] floatValue]);
        }
    }  
glEnd();

(I don't know if the Obj C makes it slower than using standard C, but in mine it's all going into display lists anyway.)

My way probably doesn't have any advantage over yours; it's just the way I came up with.
Quote this message in a reply
Moderator
Posts: 623
Joined: 2007.09
Post: #9
Man With No Name Wrote:But I don't like to program in C++ if I can avoid it. Tastes like charcoal.

Psst! Don't say that around here. People 'round here get into all kinds of fights about which language is better.Ninja I wasn't here.Sneaky
Quote this message in a reply
Moderator
Posts: 3,579
Joined: 2003.06
Post: #10
maximile Wrote:(I don't know if the Obj C makes it slower than using standard C, but in mine it's all going into display lists anyway.)

I load mine into NSDictionaries at first and then dump (order) the raw data out of that into VBO friendly buffers. This obj loader was probably the first time I found out how fast Obj-C can really be. Very nice performance!
Quote this message in a reply
Member
Posts: 24
Joined: 2008.02
Post: #11
NSDictionary, eh? Didn't think about that. Nice thing with programming is that there is more than one way of doing something.

Quote:Psst! Don't say that around here. People 'round here get into all kinds of fights about which language is better. Ninja I wasn't here.Sneaky

Sorry! I hate flame wars too.

By the way, I got the normals all parsed and integrated in the draw method. All I had to do was add another "Z" dimension to the faces array and add the function call.

Thanks for all the replies!
Quote this message in a reply
Moderator
Posts: 623
Joined: 2007.09
Post: #12
Man With No Name Wrote:Sorry! I hate flame wars too.

That was, in entirety, a jokeGrin
Quote this message in a reply
Member
Posts: 24
Joined: 2008.02
Post: #13
Yeah, I know it was a joke, but it's still not a good idea to diss someone's programming language.
Quote this message in a reply
Moderator
Posts: 623
Joined: 2007.09
Post: #14
Yeah, but you sounded just a wee bit concerned.LOL
Quote this message in a reply
Post Reply