Vertex Arrays and texturing at the same time...

I’m loading my model’s geometry into a vertex array and using indexes to those vertexes and using glDrawElements() to draw the model. Problem is, different parts of the model use different textures. So how is it possible to change textures in mid-stream? Or do you have to break your model down into it’s seperate textured groupings and then render each group seperately like this (psudo code):

BindTexture(FIRST);
glVertexPointer(pointer to first group’s verts);
drawelements(first group);

BindTexture(SECOND);
glVertexPointer(pointer to second group’s verts);
drawelements(SECOND);

?

I realize that I could do it this way, but is there a large performance cost each time you set your vertex pointer? Also, I know some will tell me to just use a single texture, but for the purposes of my game, I often have to cover large portions of a ship with a single texture and to save ALOT of texture memory, I use smaller texture and “tile” them accross the surface. Any input would be GREATLY appreciated! Thanks!

I’ve never made a game before but breaking the model down into its separate textured groupings and rendering them separtely seems quite reasonable. However I don’t think a glVertexPointer call per grouping is necessary. How 'bout having one giant vertex array per object and then setting up separate index arrays for each texture grouping.

glBeginList
glVertexPointer(shipVerticies)
glTexCoordPointer(shipTexCoords)
glNormalPointer(shipNormals)

glBindTexture(hullTexture)
glDrawElements(hullIndicies)

glBindTexture(deckTexture)
glDrawElements(deckIndicies)

glEndList

Instead of using glVertexPointer, glTexCoordPointer, etc try glInterleavedArrays. glInterleavedArrays is basically glVertexPointer, glTexCoordPointer, glNormalPointer, glColorPointer and glIndexPointer all rolled into one. So rather than having one array for verticies, another for texture coordinates and another for normals you would lump them all into one interleaved array.

typedef _InterleavedData
{
GLfloat tex[2];
GLfloat normal[3];
GLfloat vertex[3];
};
typedef _InterleavedData INTERDATA;

INTERDATA shipData[] = { … };

glBeginList
glInterleavedArrays( GL_T2F_N3F_V3F, shipData)

glBindTexture(hullTexture)
glDrawElements(hullIndicies)

glBindTexture(deckTexture)
glDrawElements(deckIndicies)

glEndList

To further reduce the number of API calls you could move all the non-tiled textures into a single texture while keeping the tiled textures separate. Then you would have one group per repeating texture plus one more group for non-tiled textures. You will have to get the tex coords right for each decal in the merged texture.

Thanks for the suggestions!!! That’s great! I hand’t thought of that. I definately think I’m going to go with interleaved arrays and then just break the indeces up into the texture groupings. Now, what about the decaling? How exactly is that accomplished? Again, thanks alot! Oh yeah, anyone know what, if any of this code should be placed in a display list? I’ve heard the state changes slow OpenGL down alot and that sticking state changes and such inside display lists speeds things up alot. But how much do I put in there?

[This message has been edited by Punchey (edited 12-17-2000).]

Well, why don’t you try putting all the textures in a single bitmap, and then assiging the proper coordinate textures to each vertex? If you do so you won’t need interleaved arrays, and you could do that with a single call to glVertexArrays()

Sansus:
Punchey already said that he didn’t want to put everything into one texture, because of the way he textures his model.

Punchey:
If the model is static, then put in in a display list.

As for decaling, you could use the multitexture extension, and in your vertex array, use two sets of texture coordinates.

j

Originally posted by Sansus:
Well, why don’t you try putting all the textures in a single bitmap …

I suggested Punchey keep his tileable textures separate so he could continue to use OpenGL’s repeatable tile texture feature eg. glTexCoord2f(sm,tn).

Originally posted by Sansus:
…then assiging the proper coordinate textures to each vertex? If you do so you won’t need interleaved arrays, and you could do that with a single call to glVertexArrays()

Even if all textures were lumped into a single texture he would definitely need to use glTexCoordArray to map the correct decal from the merged texture. glVertexArrays alone does not handle texture coordinates. This leads back to my suggestion regarding interleaved arrays. Since he needs to call glVertexArrays and glTexCoordArrays anyways why not just use the more efficient glInterleavedArrays API.

[This message has been edited by Crunch (edited 12-17-2000).]

Originally posted by Punchey:
…what about the decaling

I haven’t tried decaling on top of a texture before but I ?guess? you would draw the decal first and then draw the underlying texture second. I say draw the decal first because if you reverse the operation the decal would probably fail the depth test and not appear.

The decal would need to be RGBA for transparency to work. Usually the alpha channel is black (zero) for transparent areas and white(one) for opaque areas. Enable transparency testing (GL_ALPHA_TEST) and setup the test with glAlphaFunc. Remember to disable the transparency test when drawing the underlying texture.

A pixel with an alpha value that passes glAlphaFunc gets drawn. Pixels that fail don’t get drawn. Because GL_ALPHA_TEST does not allow for half the color value tobe drawn you may get course edges around your decal. To soften the edges up you’ll either have to blur the edges of your decals when their made or look into using blending (glBlendFunc).

Thanks alot for all this info! This will help a lot! BTW, I suppose to do decaling I need my geometry to work with me on this? This is to say, I couldn’t just have a HUGE triangle and then expect to be able to just draw a small little decal in the middle of this triangle? If you can do this, I can’t figure out how. Unless, ofcourse, you can disable OpenGL’s texture repeating feature. If you could do this, then you could specify your texture coordinates like so:
glTexCoord2f(-5,-2);

glTexCoord2f(5,2);
and that would leave the actual decal somwhere in the middel of the poly?

Thanks!

Originally posted by Punchey:
…to do decaling I need my geometry to work with me on this

Let me state again that I’ve never done decaling before but there seems to be two ways to position/orient itty bitty decals on huge surfaces. Your idea of making smaller surfaces just for the decal is one way. The other is to use the texture matrix stack (I think). With this stack you can scale, rotate, shear and translate the decal to any position. How do you do this? I have no idea but it’s probably the same as the modelview matrix.

Originally posted by Punchey:
glTexCoord2f(-5,2)

I’m not certain if I understand your usage of glTexCoord. I interpret your glTexCoord2f(-5,2) as: where to put the decal on the destination surface. If my interpretation is correct then you’re incorrect. glTexCoord designates the location of the decal from the source texture map. Suppose you had a texture with nine equal sized decals (3 rows & 3 columns) and wanted to draw the decal located in the bottom row, left column. Then your four glTexCoord would be (in counter-clockwise order)
glTexCoord2f( 0.0/3.0, 3.0/3.0 ) glVertex() // bottom-left
glTexCoord2f( 0.0/3.0, 2.0/3.0 ) glVertex() // top-left
glTexCoord2f( 1.0/3.0, 2.0/3.0 ) glVertex() // top-right
glTexCoord2f( 1.0/3.0, 3.0/3.0 ) glVertex() // bottom-right
Ignore this if my interpretation was wrong.

You can enable/disable repeating textures with glTexParameteri. You can set it to GL_CLAMP (one copy) or GL_REPEAT (many copies).

[This message has been edited by Crunch (edited 12-17-2000).]

Okay, you’re probably right as far as the fact that you’d probably want to keep all your decals in a single texture if possible and then pull them out individually… however, in my example, I was assuming the decal was in a texture of its own. That way, glTexCoord2f specifies the portion of the texture to align with the current vertex. If you had a vertex WAY off to the left of where you wanted the decal and the other vertex for the face was way to the right of where you wanted the decal, then you could disable texture repeating and do something like this:
glTexCoord2f(-10,1); glVertex3f() // top left vert
glTexCoord2f(10,1); glVertex3f() // top right vert

or something like that so that the actual image would show up somwhere in the middle of the face. Is this right? Keep in mind, this is all assuming the desired decal is all by it’s lonesome in the texture. This would obviously not work if it was in a “palette” of decals in a single texture.

You’ve got a decal by itself in a texture. Got it. The decal is non-repeating. Got it. For arguments sake let’s suppose the decal is 2"x2" and the surface is 10"x10". You want the decal to show up still 2"x2" in the middle of a 10"x10" surface and not stretched across the entire 10"x10" surface. Got it.

So to do this you would go
glTexParameteri(,GL_TEXTURE_WRAP_S,GL_CLAMP) // no repeating horizontally
glTexParameteri(,GL_TEXTURE_WRAP_T,GL_CLAMP) // no repeating vertically
// setup texture matrix here to shrink decal back down to 2"x2"
glTexImage2D(…)
glBegin(GL_QUADS)
glTexCoord2f(0,0) glVertex3f // bottom-left
glTexCoord2f(0,1) glVertex3f // top-left
glTexCoord2f(1,1) glVertex3f // top-right
glTexCoord2f(1,0) glVertex3f // bottom-right
glEnd()

Sidenote: The first parameter of glTexCoord is known as “s” and the second parameter is known as “t”.

When glTexParameter(,GL_CLAMP) then s&t means which part of the source texture you want to use. s&t valid range runs from 0.0 to 1.0. In OpenGL 0.0=0%=nothing and 1.0=100%=everything and .10=10%=a little bit.

When glTexParameter(,GL_REPEAT) then s&t means how many times you want your decal to repeat, hence sn & tm. So if sn=3 and tn=2 then your decal will be repeated 3 times across and 2 times down.

The job of positioning your decal with the correct scaling on the destination surface so that it sits in the middle or to the upper right or where ever is the job of the texture matrix stack and not glTexCoord. The only exception being if you did want your decal stretched across the entire surface (in effect the middle) then omit usage of texture matrix.

[This message has been edited by Crunch (edited 12-18-2000).]

[This message has been edited by Crunch (edited 12-18-2000).]

Okay, I have it now. The values for glTexCoord2f are clamped between 0 and 1. So do you know of any tutorials on manipulating the texture matrix? Thanks again for all the help!

There isn’t a whole lot say about using the texture matrix. The OpenGL Guide offers a whole two paragraphs on the topic. But here is the general idea

glMatrixMode(GL_TEXTURE) // switch to texture matrix
glLoadIdentity // clear matrix
// do operations to texture matrix here like
glScalef(0.5, 0.5, 1.0) // shrink texture by half
// anything you can do with the modelview matrix is also
// valid when operating on the texture matrix
glMatrixMode(GLMODELVIEW) // switch back to modelview matrix
// do operations to your modelview matrix here
// draw your texture and quads
glTexParameter
glTexImage2D
glBegin(GL_QUADS)
glTexCoord glVertex x4
glEnd

One more thing: values for glTexCoord are clamped to 0 and 1 only for non-repeating textures. For repeating textures values usually exceed 1. So a value of 4 means your texture would be drawn 4 times one next to the other.