I have a model in .bam format that I created in Blender. I assigned it UV coordinates and a texture using Blender. It looks fine in Panda3D, until I try switching out the texture for another image with a different color scheme. With the following code, the new texture is multiplied by the old one, even though it should completely replace the old texture:
As expected, this completely replaces the original texture. After I do this, however, calling buoyModel.setTexture(anotherTex, 2) does nothing, even if I set the Geom’s TextureAttrib to a blank one (TextureAttrib.make() or TextureAttrib.makeDefault()). Is this a bug? I’d like to be able to change the texture without digging in to the Geoms.
In order to completely replace an existing texture on a model, you have to have a pointer to the TextureStage that was used to apply the texture to the model, and use that same TextureStage.
Since your example code creates a new TextureStage, it will of course add to the texture stack, rather than replacing the existing texture. Think of each TextureStage as a slot to hold a texture. If you want to replace a particular texture, you have to store it in the same slot. Each time you apply a new TextureStage, you are stacking a new texture slot into the box.
Normally, if your model doesn’t apply any custom-named UV’s or any other fancy texture properties, then the egg loader will apply its textures to the default TextureStage, which is why you can usually override a texture on a simple model with simply model.setTexture(newTex, 1), which also uses the default TextureStage.
Since your model uses custom-named UV’s, it will have a custom TextureStage implicitly created to apply this texture. So you can find that TextureStage in the model and reuse it with something like:
Hey David, thanks for help. I didn’t realize that my exported model had a special TextureStage.
For anyone else having this problem, you might find the following code handy. It removes textures from every node in a model, so setTexture(tex) will work.
from panda3d.core import GeomNode, TextureAttrib
def stripTextures(model):
''' Remove the textures from every node at and under the given NodePath. '''
node = model.node()
if isinstance(node, GeomNode):
for i in xrange(node.getNumGeoms()):
renderState = node.getGeomState(i)
if renderState.hasAttrib(TextureAttrib):
newRenderState = renderState.removeAttrib(TextureAttrib)
node.setGeomState(i, newRenderState)
for child in model.getChildren():
stripTextures(child)
The first line disables all textures at this node and below; the second line sets only myTex. The same override parameter, 1 in this case, must be supplied to both functions; the override value must be higher than 0 (or whatever is already in the model) in order to make your new texture operation supercede the textures already on the model.
I see a grid, and this works for my model, too. I realized that I’m actually turning the texture off on the model, and then setting the new texture on a nodepath a couple levels above the model. Of course, the “off” setting lower in the tree was overriding the texture I was setting above it.