Wednesday, December 24, 2008

Texture Coordinate Arrays or Things Nobody Tells You

For some reason, a lot of OpenGL stuff just isn't well documented. Yes, I read the Red Book chapter on texturing. It didn't have a single reference to glTexCoordPointer(). I also read everything else I could find online, and wore the edges right off of some search terms.

As you can see here, my first attempt at loading texture mapped Wavefront OBJ files wasn't exactly a success:


The man page for glTexCoordPointer() tells you that it's used to feed an array, but it doesn't tell you the format of the array.
It hasn't been a complete failure so far - I've got the texture loading and being displayed, but the coordinates are not right.

I think I have finally figured out the problem. The array that you pass into glTexCoordPointer() has to correspond to the array passed into glVertexPointer(). If you're using two-point mapping (UV, no W), then your texture coordinate array has to have 2/3 the number of GLfloats that your vertex array has, since for every three-float vertex, you need one two-point texture coordinate, and they need to be in the same order.

Easy enough. Except that the vertices might not have the same texture coordinates for every polygon that it's used in.

Hmm... Apple recommends that you use glDrawElements() to avoid duplicating vertices. But, if a vertex had different texture coordinates in different polygons (and with complex objects, it usually will), you have to duplicate the vertices for every different set of texture coordinates that correspond to that vertex.

That's a little confusing, huh? Remember this picture:

Well, in our vertex array, the vertex marked "A" exists only once in our vertex array even though it forms a part of six different triangles. That is good for us because it reduces the amount of floating point data that OpenGL has to shuffle around. In our calls to glDrawElements(), we refer to that vertex using an integer index value which tells OpenGL to grab that specific vertex out of the vertex array, which is a quick lookup.

Now, let's say we want to texture this whole mesh—all six triangles—with a single UV-mapped image. Chances are, the texture coordinate for vertex A with regards to triangle 1 will be different than the texture coordinates for that vertex for triangle 2... and 3, and 4 and 5, and 6. In most situations, we can't specify just one texture coordinate value that will work for that vertex in all six triangles. It just can't be done the way we're approaching this.

So, what's the answer? It's actually a little gnarley. I'm going to have to parse all the unique combinations of vertex and texture coordinates in the faces portion of the OBJ file and then duplicate any vertices that have more than one corresponding texture coordinate. Of course, all the indices that point to such a vertex will have to be updated to point to the correct version of that vertex, so that when we call glDrawElements(), OpenGL is able to grab the right texture coordinates for the polygon being drawn.

I now know what I have to do, it's just a matter of finding the time to do it. Probably by the end of the weekend I'll have the texture mapping working.

No comments:

Post a Comment