Texture paths [SOLVED]

I am trying to implement something I’ve seen in some commercial games. Basically a single model is used for a character (say a soldier). But there are several texture sets which are made for the model, so you can have differnt teams,colors, etc.

The textures are stored in a subfolder under the model’s path.

What I’d like to do is programmatically allow the user select which texture to use by letting them specify a folder.

Now I haven’t tried it yet, but think I figure out the setTexture sample code in the manual to switch this for simple models with 1 texture if it’s always the same filename. seems simple enough.

But if some models have multiple textures, is there a way I can just change the paths used by all textures in a model?

Say the default textures are:
/std/body.tga
/std/helmet.tga
/std/boots.tga

the user chooses to use the set in /green_soldier/
I would need to load and set:
/green_soldier/body.tga
/green_soldier/helmet.tga
/green_soldier/boots.tga

so whats the best approach ? (assuming I don’t know beforehand the name of the texture files or the number of files a model uses)

find the proper mesh inside the character with char.find("**\propermesh")
set texture on that mesh with setTexture().

One problem you might run into if egg opt char optimized the textures some how into a single tex.


In my game i also have “team stripes.” I dont switch textures but use shader to color them properly at run time.

Hi, thx for the reply!

Is there a way to get a list of all the parts in the model that have textures? I could then interate through the list , updating the texture for each.

Still trying to work through this.

for example, if x is an Actor I’ve constructed:
print x.findAllTextures returns:
male_basic_bump
male_basic
which is the name of the 2 textures on this model (without the file extension, .png or paths)

print x.getTexture() returns:
None

As per my previous post, is there a way to return a list of the parts in the model that have textures? I could then interate through the list , updating the texture (using setTexture) for each with a new user-selected path.

It’s possible to iterate through all the parts that have textures, but you’d have to flag them all anyway. If you’re going to flag them all, you already know what they are, don’t you? Why not just iterate through the list of names that you flagged?

David

Sorry, not understanding what you mean by “flagging them”. How would I do that?

I wouldn’t know beforehand which textures are present in the model, as we have a few different ones we’re using (some with extra parts)

The answer is different depending on whether you’re talking about Actors or ordinary models. With an Actor, you need to “flag” all the pieces that you will modify individually; otherwise all the pieces will all be combined into a single GeomNode. You would do this by passing the egg file through egg-optchar, with the -flag option. I believe this is described in the manual. With an ordinary model, you (usually) don’t have to do this.

That being said, it is also possible to iterate through the model and find just the textures, as you suggested, and replace them one-at-a-time, even if you have not flagged any pieces. It is a little complicated, though, because you have to use the low-level state interface to pull out the individual states within a single GeomNode. Still, this code (untested) ought to do the trick. It should work equally well for an Actor or for an ordinary model.

for np in model.findAllMatches('**/+GeomNode'):
    gn = np.node()
    for gi in range(gn.getNumGeoms()):
        state = gn.getGeomState(gi)
        ta = state.getAttrib(TextureAttrib.getClassType())
        if ta:
            for si in range(ta.getNumOnstages()):
                stage = ta.getOnStage(si)
                tex = ta.getOnTexture(stage)
                filename = tex.getFilename()
                filename2 = Filename('/my/new/path', filename.getBasename())
                tex2 = loader.loadTexture(filename2)
                ta = ta.addOnStage(ta.addOnStage(stage, tex2))
            state = state.setAttrib(ta)
            gn.setGeomState(gi, state)
            

David

Thx so much for the code, I’ll try it out!

I don’t think I would have figured out the object hierarchy for a while :slight_smile:

The code worked great!
I’m going to make it a callable function and put in some error-checking.

There were a couple of line I had to chg to get it to run, in case anyone needs something like this in the future (see below - I commented out the lines I changed and my corrected line is underneath - just typos i think)

for np in model.findAllMatches('**/+GeomNode'): 
    gn = np.node() 
    for gi in range(gn.getNumGeoms()): 
        state = gn.getGeomState(gi) 
        ta = state.getAttrib(TextureAttrib.getClassType()) 
        if ta: 
            #for si in range(ta.getNumOnstages()): 
            for si in range(ta.getNumOnStages()): 
                stage = ta.getOnStage(si) 
                tex = ta.getOnTexture(stage) 
                filename = tex.getFilename() 
                filename2 = Filename('art/characters/batman/skins/standard', filename.getBasename()) 
                tex2 = loader.loadTexture(filename2) 
                #ta = ta.addOnStage(ta.addOnStage(stage, tex2)) 
                ta = ta.addOnStage(stage, tex2)
            state = state.setAttrib(ta) 
            gn.setGeomState(gi, state) 

Thx again!

More old code I’m revisiting.

The final code above is using addOnStage, so my understanding (which could be wrong) is that this is applying a second texture to the geomnode?

Is there a way I could simply replace the texture on the geomnode completely , not add a second texture. I use some gloss/normal maps and have noticed some strange effects , which I’m thinking may be caused by layering these textures rather than completely replacing them.

Still looking at this.
Specifically, it seems that the basic (diffuse) texture I use is replaced OK, but I also have normal(bump) and gloss (reflection) textures which are specified in the egg file.

When I use the code above, I still see the effects of those textures in the model, even though I have a different set of normal and gloss textures in the new folder I’m specifying.

Not sure if those type of textures need to be handled differently? Or is there a way to explicitly clear them before I call addonStage for the new texture?

Appreciate any help.

You have to find all of the TextureStages on the model. Each TextureStage can have a different texture. If you apply only a texture with the one-parameter setTexture() call, you have only replaced the default TextureStage, without changing the others.

The code you paste above is a very clumsy way to find all of the TextureStages. An easier way is to use model.findAllTextureStages().

Read up about multitexture in the manual to learn more about the way TextureStages work.

David

Thanks, I’ll check that out.

Just got back to this.

I think the problem I see (strange effects of bump or glow maps) is being caused by textures being applied in the wrong order.

Basically, the code above does not guarantee what order it will loop through e texturestages in.

Not at my pc right now, so I can’t try solutions (will try later)
But is there a way to make sure the list of stages I get back is always in the same order?

Never mind, it seems that some rogue alpha layers were causing the weird things I was seeing. So the code above seems good to go.