I’m using a timer to loop through a large number of texture swaps. On each iteration it swaps to a different texture state to make it appear that it is blinking.
The problem is that I drop from 60fps down to 1fps.
Is there a better way to do this than using setTexture?
Perhaps a shader?
Layer the off state on top of the on state and just hide it / show it to create a blink?
# called from doMethodLater every .25 seconds
#loop through 96 textures:
if not textureBlink:
t1 = textureOn
if (defaultTS == None):
defaultTS = dict[key]['node'].findTextureStage(textureStageDefault)
dict[key]['node'].setTexture(defaultTS,t1, 1)
textureBlink = True
else:
t1 = textureOff
if (defaultTS == None):
defaultTS = dict[key]['node'].findTextureStage(textureStageDefault)
dict[key]['node'].setTexture(defaultTS,t1, 1)
textureBlink = False
#endloop
My guess is your performance hit is coming from the findTextureStage calls not the setTexture calls. In that case the solution would be to pre-store the result of your findTextureStage call in that dictionary you are using.
It could also cause problems if you have the auto-shader in effect on this node, since swapping the texture (or doing any other state change) will require the node to recompile a new shader.
I double checked, findTextureStage is only called once and saved to a global.
You’re right drwr, removing the auto-shader on render fixed the issue.
I lose my nice normal mapping and lighting on the model though.
So I guess I have to create my own shader for this node in order to get my model looking nice again. I ran a test with a simple shader and I didn’t run into the performance issue problem, but the shader also doesn’t do anything.
I looked through the forums / manual for a replacement shader, but haven’t found one that handles normals, gloss and lighting, but I also don’t fully understand them.
Can you point me in the direction of a shader that does this?
Or is there a way to export the auto generated shader that my program is using?
You can dump all of the shaders by (temporarily) putting “dump-generated-shaders 1” in your Config.prc file, then you can choose the appropriate shaders from the result and load them as shader files directly.
But you also can solve this problem by simply holding onto the RenderState that corresponds to the previous state, which will allow it to re-use the previous shader when you return to that state.
One way to do this is instead of calling setTexture() on the fly, walk through all of your textures at init time, and save the RenderState for each pair. Like this, at init time:
#loop through 96 textures:
if not textureBlink:
state = dict[key]['tex_on_state']
dict[key]['node'].setState(state)
textureBlink = True
else:
state = dict[key]['tex_off_state']
dict[key]['node'].setState(state)
textureBlink = False
#endloop
Maybe it’s a stupid idea, but how about using a sequence node?
It’s a bit of copy-paste work with the eggs but then you just call loop() and it’s done.
If you’re changing state that doesn’t require a shader rebuild, then it’s not an issue in 1.8 any more. But changing the texture state still requires a shader rebuild.
This could probably be further optimized–certain changes to the shader state, for instance, swapping one texture out for a similar texture–don’t necessarily require a shader rebuild, but certain other changes to the texture state do (like adding or removing from the total number of textures), and right now it doesn’t make this distinction and just rebuilds the shader state in all cases.