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.



5 comments:

riq said...

Hi Jeff,
If you need further help with glTexCoordPointer() I can give you a hand.
I've been using it in within cocos2d without major problems.

unparagoned said...

I'm having pretty much the exact problem you are having. Do you have any more info on how you solved the shared vertex problem?

Rafael said...

Hi Jeff,

I think there still is an issue with the approach of duplicating the vertices.

When I export an OBJ file from Blender, the vertices that are on the seams used to unwrap my mesh (to do UV mapping) are duplicated in the OBJ file.

I guess they have different texture coordinates, so your wavefront obj loader will duplicate them.

But as a result, the seams are visible in openGL (because the vertices are duplicated, so there are two normals, and so a little shade appears - ask me if you want a screenshot).

I'm just starting with OpenGL, so I might get something wrong here...
Any help appreciated !

Thanks

gonzobrains said...

This sample project just shows a blank white screen in my simulator.

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels