Multiple UV coordinates in same TextureStage

Ok, this is my idea - I am building a level made out of cubes. I’d like to be able to set different textures to these cubes and flattenStrong them at the end. But models with different textures cannot be flattened, so I got the idea to create just one texture image, made out of 2 different textures and I would manipulate UV coords on my model. I added different set of UV coords to my egg (so I had 2, Tex01 and Tex02) and my code goes something like this:

ts = TextureStage('ts')        
for x in xrange(0, maxX):
    for y in xrange(0, maxY):
        if getHeight(x,y ) > 0:
            ts.setTexcoordName("Tex02")
        else:
            ts.setTexcoordName("Tex01")
        model = loader.loadModel('tile')
        model.setPos(x, y, 0)
        model.setTexture(ts, tex)
        model.reparentTo(main_node)
main_node.clearModelNodes()
main_node.flattenStrong()

This however doesn’t work. TextureStage always sets the coord name which it gets first, subsequent setTexcoordName calls are ignored. It works if I put TextureStage in the loop, but then I cannot flatten.

One solution might be to make separate egg models with different default UV coordinates in them, and load them according to the condition in the loop. Any other smarter solutions to this?

What you are attempting is called Mosaicing, or in the somewhat quirky nomenclature of Panda, palettization.

The technique does work, but you can’t have two different named UV sets. Instead, use a single named UV set for all vertices, and choose the UV coordinates for each vertex to access the appropriate smaller texture within the overall texture. For instance, if you place your two textures side-by-side in the larger texture, then any vertices that are meant to access the left texture will have UV’s in the range (0,0) to (0.5,1), and any vertices that are meant to access the right texture will have UV’s in the range (0.5,0) to (1,1).

But you don’t have to do this by hand. The tool egg-palettize, for instance, will do it for you automatically. It’s a complicated tool because it does a lot of complex stuff, but at its heart it will read a series of egg files, combine all of the textures into a single texture wherever possible, and rewrite the UV’s to reference the newly combined textures correctly.

There are also mosaicing tools built into various modeling packages to achieve similar things at a higher level.

David

Ok, I will look at egg-palettize, that sounds very useful.

One question though, you mention I should choose UV coordinates for each vertex to access parts of the texture. I am not sure how to do this in runtime, my UV coords are written in egg file. That is why I was thinking to assign different set in egg file and then reference one or the other during runtime.

This sort of technique is generally done at model-build time, not at runtime. Hence the recommendation for egg-palettize, which is a model pre-processing tool. Once you have preprocessed all of your egg files to all reference the same single texture (or the same small handful of textures), then your runtime flattening will be much more effective.

If you really want to combine textures at runtime, you will have your work cut out for you. You can do it, but you’ll have to modify the UV coordinates on the fly, for instance by rewriting the vertex values.

This is necessary because the selection of the particular texture coordinate set is part of the graphics state, and thus if you have two different vertices that each use different a texture coordinate set, then they must be rendered in two different passes (so Panda can change the graphics state between them). This completely defeats the point of all this flattening, which is to make it possible to render everything in just one pass. In order for this to work, everything has to be all the same graphics state.

David

Thanks for the answer David, I will look into it.

The reason I asked about it is because previously I have been creating my geometry (tiles) procedurally, and there I was able to assign different UVs to vertices so I could have one tile reference one part of the texture, and second tile reference another part, and combine them all under one geom. So I thought there might be some kind of solution when using models instead of building my own geometry by hand.

One runtime approach might be to use an appropriate setTexOffset() and setTexScale() to apply the needed transform to the UV’s of each of your cube faces (instead of creating a custom UV set). These transformations will be applied to the vertices by flattenStrong(), so they do not require a special state and do not interfere with flattening.

David

Ok, you have certainly given me enough hints to go on investigating what my approach should be. I will probably end up using palletize, as I think I can live with preprocessed models.

Thank you again for your input David!

If you’re gonna use a texture mosaic/atlas than maybe changing the whole model would be a quicker(code-wise) way to have the same effect?

I am still prototyping and building proof-of-concept scenarios, so not really sure if I will end up using mosaicing.

For now setTexOffset() works ok, but later on if I go with this approach I will probably palettize my models.