When creating a copy of a TextureStage using the copy constructor (TextureStage(original)), the copied stage behaves differently depending on whether the original stage has previously been applied to a model.
from direct.showbase.ShowBase import ShowBase
from panda3d.core import TextureStage, Vec4F, PNMImage, Texture, AmbientLight
class App(ShowBase):
def __init__(self):
super().__init__()
add_stage = TextureStage('add_constant')
add_stage.setSort(2)
add_stage.setCombineRgb(
TextureStage.CMAdd,
TextureStage.CSPrevious,
TextureStage.COSrcColor,
TextureStage.CSConstant, # must add colour from stage
TextureStage.COSrcColor,
)
add_stage.setCombineAlpha(
TextureStage.CMReplace,
TextureStage.CSPrevious,
TextureStage.COSrcAlpha,
)
add_stage.setColor(Vec4F(0, 0, 1, 1)) # blue colour
copied_stage = TextureStage(add_stage)
self.dump_stage(add_stage)
self.dump_stage(copied_stage)
dummy_image = PNMImage(1, 1, 4)
dummy_image.set_xel_a(0, 0, 1, 0, 0, 1) # red colour
dummy_texture = Texture()
dummy_texture.load(dummy_image)
self.cube_add = self.loader.loadModel('models/box')
self.cube_add.reparentTo(self.render)
self.cube_add.setPos(1, 0, 0)
# self.cube_add.setTexture(add_stage, dummy_texture) # apply add_stage
self.cube_copied = self.loader.loadModel('models/box')
self.cube_copied.reparentTo(self.render)
self.cube_copied.setPos(-1, 0, 0)
self.cube_copied.setTexture(copied_stage, dummy_texture)
ambient = AmbientLight('ambient')
ambient.setColor((0.5, 0.5, 0.5, 1))
self.render.setLight(self.render.attachNewNode(ambient))
@staticmethod
def dump_stage(stage: TextureStage):
print("name:", stage.getName())
print("sort:", stage.getSort())
print("mode:", stage.getMode())
print("rgb mode:", stage.getCombineRgbMode())
print("rgb source 0:", stage.getCombineRgbSource0())
print("rgb operand 0:", stage.getCombineRgbOperand0())
print("rgb source 1:", stage.getCombineRgbSource1())
print("rgb operand 1:", stage.getCombineRgbOperand1())
print("alpha mode:", stage.getCombineAlphaMode())
print("alpha source 0:", stage.getCombineAlphaSource0())
print("alpha operand 0:", stage.getCombineAlphaOperand0())
print("alpha source 1:", stage.getCombineAlphaSource1())
print("alpha operand 1:", stage.getCombineAlphaOperand1())
print("color:", stage.getColor())
print("uses color:", stage.usesColor())
if __name__ == "__main__":
app = App()
app.run()
In the provided example, the copied TextureStage is expected to apply the constant blue colour set via setColor(), making the cube appear blue. However, when the original stage has not been applied to any model (i.e., the line # self.cube_add.setTexture(add_stage, dummy_texture) is commented out), the copied stage does not apply the blue colour – the cube remains red, as if the constant colour is ignored and dummy_texture colour is added. If you uncomment that line (applying the original stage at least once), the copied stage then works correctly and the cube turns blue. Calling dump_stage() on both stages reveals that all attributes are identical in both cases. This suggests that the problem is not a missing data copy, since the copied and original stages report identical values through the public API. There appears to be some additional internal state that differs between a stage that has been used and one that has not.
I originally used a prototype stage and created copies of it in my game. As a workaround, I now create each TextureStage using a factory method instead. Is this intended behavior? I could not find any documentation mentioning this limitation. If it is a deliberate design choice, it would be helpful to document it. Otherwise, could this be considered a bug?
Panda3D version: 1.10.16

