setTexture Sequence does nothing

This one creates the explosion, but the texture stays at stage 1. However, the remaining components in the Sequence (2,3,4) do get called in 0.5 sec intervals, but the texture does not change. As if explotex2,3,4 still call for 1.
explotex1-4 are the same color texture combined with different alpha textures.

def createExplosion(self, source, dur=2.0):
	explocm = CardMaker("explocm")
	explocm.setFrame(-1,1,-1,1)
	explogen = explocm.generate()
	self.explo = render.attachNewNode(explogen)
	explotex1 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a1.png")
	explotex2 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a2.png")
	explotex3 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a3.png")
	explotex4 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a4.png")
#	self.explo.setTexture(explotex4)
	self.explo.setTransparency(TransparencyAttrib.MDual)
	self.explo.setScale(0.01)
	self.explo.setTwoSided(True)
	self.explo.setBillboardPointEye()
	self.explo.setLightOff()
	self.explo.flattenStrong()
	self.explo.setDepthTest(True)
	self.explo.reparentTo(render)
	self.explo.setPos(source.getPos())
		
	exploscale = LerpScaleInterval(self.explo, dur, 2.0, 0.01)
	exploscaleseq = Sequence(exploscale, Func(lambda: self.explo.removeNode())).start()
	explotexseq = Sequence(Func(lambda: self.explo.setTexture(explotex1)),Wait(0.5),
	Func(lambda: self.explo.setTexture(explotex2)),Wait(0.5),
	Func(lambda: self.explo.setTexture(explotex3)),Wait(0.5),
	Func(lambda: self.explo.setTexture(explotex4))).start()

Not sure this is your problem, but the lambda syntax requires you to bind all of your parameter variables used in the call, something like this:

Func(lambda explotex2=explotex2: self.explo.setTexture(explotex2))

If you fail to do this, then the explotex2 variable is evaluated in the scope of the calling environment, not the scope of the binding environment, and is likely to fail.

David

Your code does not yield the desired results.

Nor does:

explotexseq = Sequence(
		Func(lambda explotex1: self.explo.setTexture(explotex1)),Wait(0.5),
		Func(lambda explotex2: self.explo.setTexture(explotex2)),Wait(0.5),
		Func(lambda explotex3: self.explo.setTexture(explotex3)),Wait(0.5),
		Func(lambda explotex4: self.explo.setTexture(explotex4))
		).start()

That one doesn’t work either:

explotexseq = Sequence(Func(self.explo.setTexture, explotex1),Wait(0.5),
		Func(self.explo.setTexture, explotex2),Wait(0.5),
		Func(self.explo.setTexture, explotex3),Wait(0.5),
		Func(self.explo.setTexture, explotex4)).start()

I don’t get crashes or errors, but the texture just stays at stage1.

It’s the setTexture() priority.
Try :
Func(setTexture, tex, 1)

Doesn’t help.

The code a bit different, but doesn’t work either:

explo = render.attachNewNode(explogen)
explo.setTexture(explotex1, 1)
# dur = 2.0

exploscale = LerpScaleInterval(explo, dur, 2.0, 0.01)
explotexseq = Sequence(Wait(0.5),
	Func(explo.setTexture, explotex2, 1), Wait(0.5),
	Func(explo.setTexture, explotex3, 1), Wait(0.5),
	Func(explo.setTexture, explotex4, 1), Wait(0.5),
	Func(explo.removeNode))
explopar = Parallel(exploscale,explotexseq).start()

The node scales up over 2 seconds as it should, but only the first texture is set. Note that in the sequence the first 0.5 seconds there is no texture set because it was set at creation before (line 2). When I comment line 2 the node is created with a white texture as expected. After 0.5 seconds the texture is set with explotex1 - where it should be explotex2, as stated early in the sequence. So I guess the other setTexture’s are applied too, just that always explotex1 is used and not 2,3,4.

Well, are you sure that explotex2, 3, and 4 are actually different textures and not somehow the same texture as explotex1?

David

Yes, I am sure. This the code right now:

def createExplosion(self, source, dur=2.0):
	explocm = CardMaker("explocm")
	explocm.setFrame(-1,1,-1,1)
	explogen = explocm.generate()
	explo = render.attachNewNode(explogen)
	explotex1 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a1.png")
	explotex2 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a2.png")
	explotex3 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a3.png")
	explotex4 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a4.png")
	explo.setTexture(explotex1, 1)
	explo.setTransparency(TransparencyAttrib.MDual)
	explo.setScale(0.01)
	explo.setTwoSided(True)
	explo.setBillboardPointEye()
	explo.setLightOff()
	explo.setDepthTest(True)
	explo.reparentTo(render)
	explo.setPos(source.getPos())
	
	exploscale = LerpScaleInterval(explo, dur, 2.0, 0.01)
	explotexseq = Sequence(Wait(0.5),
	Func(explo.setTexture, explotex2, 1), Wait(0.5),
	Func(explo.setTexture, explotex3, 1), Wait(0.5),
	Func(explo.setTexture, explotex4, 1), Wait(0.5),
	Func(explo.removeNode))
	explopar = Parallel(exploscale,explotexseq).start()

When I comment the line where explotex1 is defined and then change the first setTexture to explotex2, like this:

def createExplosion(self, source, dur=2.0):
	explocm = CardMaker("explocm")
	explocm.setFrame(-1,1,-1,1)
	explogen = explocm.generate()
	explo = render.attachNewNode(explogen)
#	explotex1 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a1.png")
	explotex2 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a2.png")
	explotex3 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a3.png")
	explotex4 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a4.png")
	explo.setTexture(explotex2, 1) # !
	explo.setTransparency(TransparencyAttrib.MDual)
	explo.setScale(0.01)
	explo.setTwoSided(True)
	explo.setBillboardPointEye()
	explo.setLightOff()
	explo.setDepthTest(True)
	explo.reparentTo(render)
	explo.setPos(source.getPos())
	
	exploscale = LerpScaleInterval(explo, dur, 2.0, 0.01)
	explotexseq = Sequence(Wait(0.5),
	Func(explo.setTexture, explotex2, 1), Wait(0.5),
	Func(explo.setTexture, explotex3, 1), Wait(0.5),
	Func(explo.setTexture, explotex4, 1), Wait(0.5),
	Func(explo.removeNode))
	explopar = Parallel(exploscale,explotexseq).start()

… then only explotex2 is displayed and looks different of course (red, tex1 is yellow). The color texture ("_c") is always the same but the alpha ("_a1") is different. Maybe its a bug related to that?
Maybe I am still using the priority wrong? Whats that for? Tons of other setTextures in my code dont have that.

Nooo, just tried it and it fails too.
But, it works if I unload it immediately after loaded.
You don’t need the priority override, since the geom doesn’t have any texture.

So :

   explotex1 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a1.png")
   loader.unloadTexture(explotex1)
   explotex2 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a2.png")
   loader.unloadTexture(explotex2)
   explotex3 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a3.png")
   loader.unloadTexture(explotex3)
   explotex4 = loader.loadTexture("../mceffects/explosions/explo1_64_c.png", "../mceffects/explosions/explo1_64_a4.png")
   loader.unloadTexture(explotex4)

Yeah, that works. Thank you very much. That technique can’t stand though :slight_smile:

That’s part of Panda’s design, though: it caches the texture based on the first filename only. It assumes that when you combine two files to make a four-channel image, you are doing so only to avoid problems with image file formats that don’t support alpha, and so you will always combine the same two images together for a particular texture. So the second (and later) time you load a texture with the same first filename, it just returns the same texture that you loaded already.

It would be possible to make it cache the textures based on both filenames, but this gets considerably more complicated. I think as long as you understand it is caching this way, there should be no problem.

It is true, though, that it is a very subtle thing that can lead to mysterious confusions. Look how long it took for you to mention that you were loading textures this way–so clearly it wasn’t apparent that the problem was coming from the way you were loading them.

David

Huh? It’s in my very first post.
And no, I wouldn’t think of that being a problem when I assign four different variable names. There are users not knowing Panda internals.

How else is one supposed to do this? You have a particle system with textures for animation stages, now how do you swap them? I know the MeshDrawer approach but lets say you dont want to use that.
ynjh pointed me to loadTextureMovie and the swap textures sample. Is that it?

EDIT: Playing the animation with the code above I get a pretty big slowdown, like from 150 FPS to 60 FPS. Multiple transparent stuff on each other I am at 15 FPS. But I have to keep it that way, since those are explosions that occur in masses.

You’re right, my bad. I overlooked it, my apologies.

Right, I didn’t mean to accuse you of being naive. I meant to point out that we have a documentation flaw, as evidenced by your confusion. If our documentation had been better, you wouldn’t have been confused.

I guess I would have done this by loading four different texture files, each with a different alpha channel but a duplicate copy of the color channels. You get bonus points for thinking outside the box and thinking to share the same color channel file for all four textures, but that wasn’t part of the intended design of the texture loading system. I’m not accusing you of doing anything wrong; I’m simply pointing out that the design and the interface are incompatible: the interface suggests a usage pattern that doesn’t match the design. This is a flaw of Panda, not of you. :slight_smile:

The way you’re swapping textures is fine. It was never a problem with the way you’re swapping them; it was a problem with the way you were loading them: you thought you were loading four different textures, when in fact you were loading only one.

Another option to consider, to reduce the sheer number of particles onscreen, is to pre-render the explosions into a series of texture images, then create a texture flip with egg-texture-cards and just load and play that.

David

Oh humbled I am by thy kindness :slight_smile:

Never really liked egg-texture-cards. As far as I understand it you have to supply your texture stages as seperate files, like 8 files for 8 stages. And where do I set a seperate alpha file? Which then is 16 files?

I’m not sure what you mean by “texture stage” here. It doesn’t seem to be the same as Panda’s meaning of the phrase “texture stage”.

egg-texture-cards simply generates a series of cards, one per texture that you supply. It is useful to provide a way to load your textures through the model system, instead of via loader.loadTexture(), which allows you to specify parameters like mipmapping and such.

egg-texture-cards can also put a SequenceNode on top of the cards to automatically cycle through the animations at the speed you specify, so you can use egg-texture-cards to generate a model that, when loaded, automatically plays your textures like the frames of a movie. That’s the use I’m proposing here.

Bind the alpha channel into the texture image, and store it as a png file or something that supports alpha. Since each image is going to be a single frame of the overall animation, each image will have a different color channel anyway.

David

Yeah, me too.

Well that’s work. A million times I’ve heard to stay away from combining the RGB and the A channel in a single image and instead go for two files. That’s what I do almost everywhere.

Well I now took the time to produce some texture sequences and the egg-texture-cards. Well it’s a nice thing and performance seems better too. Not on the transparent smoke or blast texture though. No textures to cycle here, I am using CardMaker.
I don’t get it. Akuryou’s flight game had all those transparent clouds overlapping each other and still good performance?!

EDIT:
Propably got a clue on the performance. It’s when I lerp the transparency to fade stuff in and out:

ringtransp = LerpFunc(self.setTransparency, extraArgs=[mynode], fromData=1.0, toData=0.0, duration=dur, blendType="easeOut").start()

def setTransparency(self, alphavalue, target):
		target.setColor(1,1,1,alphavalue)

Any better way to do this?

Anyway … after an egg-tex-card animation is done the node stays there. How do I remove it precisely when the animation is done? Sure not through

Sequence(Wait(duration), Func(delete))

? Because then you have to figure out the duration first which is a pain?

Really? I haven’t heard that before. I’ve never had a problem with four-channel images.

By chance are you using the auto shader? Try disabling it for the particle effect with:

node.setShaderOff()

Sorry, yes, you do. But the computation is simple: frame_rate * number_of_frames.

David

Well very early in I had massive problems that I thought had something to do with Panda on Macs. Since then I used the two texture approach. Recently I don’t have these problems anymore, so maybe it’s just me doing things right. But hey, the manual says the same: too many problems with image editing software and the way it stores transparency, so don’t do it.

Oh, that did miracles for my FPS in some places. The main menu went from 70 to 100. No more FPS downs when lerping transparencies. An old problem I had is a massive framedrop when going from the game back to the menu. Let’s say in the menu 70 FPS, game 100 FPS, back to menu 30 FPS. ShaderOff() on all transparent elements in the menu and the FPS dont drop visibly. I use render.setShaderAuto everywhere.

Well OK, but maybe a something is needed that plays and deletes the egg-texture-card.

Sounds handy. I bet you could write such a convenient wrapper in no more than a couple dozen lines of code. :slight_smile:

David