[solved] shaderattrib problem in 1.5

hello.
I continue my work, tying to make my code works in panda 1.5

I have another problem. This time, though, i know it’s all thanks to my crappy coding.

The aim is to make a button that switch between a shadow_mapping shader and the default shader. ( the shadow_mapping is the same shader with just a shadow map included )

The problem is to get the same shaderInput
I’m wondering how’s the “right way” to do that.

Here’s my code., in 1.42 there is no problem, (apart from the ugliness,… ).

Mesh ‘creation’:

self.mesh.setShader(loader.loadShader('mesh.sha'))
ts1 = TextureStage('texture')
self.mesh.setTexture(ts1,self.default_textures[0])
ts2 =TextureStage('normalmap')
self.mesh.setTexture(ts2,self.default_textures[1])
self.mesh.setShaderInput('direction',self.direction[0],self.direction[1],self.direction[2])      self.mesh.setShaderInput('directiono',self.direction_ortho[0],self.direction_ortho[1],self.direction_ortho[2])
self.mesh.setTag("material_type","mesh")

and the ‘switch’, activate…

myShaderAttrib = ShaderAttrib.make()
myShaderAttrib = myShaderAttrib.setShaderInput('light',self.LCam)
myShaderAttrib = MyShaderAttrib.setShaderInput('Ldepthmap',self.Ldepthmap)
myShaderAttrib = myShaderAttrib.setShaderInput('offset',Vec4(self.Xoffset,self.Yoffset,self.Doffset,0))

shadowshader = loader.loadShader('shadow_mapping.sha'))
standard_attrib = myShaderAttrib.setShader(shadowshader)
standard_state = render.getState().addAttrib(standard_attrib)

base.cam.node().setTagStateKey("material_type")
base.cam.node().setTagState('mesh',standard_state)

[other material_type]

…and deactivate:

base.cam.node().setInitialState(render.getState())
base.cam.node().setTagState('mesh' ,render.getState())

error in 1.5:

Assertion failed: Shader input directiono is not present.
 at line 323 of c:\temp\mkpr\panda\src\pgraph\shaderAttrib.cxx
Assertion failed: Shader input direction is not present.
 at line 323 of c:\temp\mkpr\panda\src\pgraph\shaderAttrib.cxx

thanks

First, about what changed between 1.4.2 and 1.5.0 - I added some more error checking code, that’s all. In 1.4.2, if you used a shader input and then didn’t supply it, it would supply a random value. In 1.5.0, if you use a shader input and then didn’t supply it, you get an error message. That’s why you’re seeing an error message now and not with 1.4.2. But the error was still there in 1.4.2, it just wasn’t printing anything.

Somehow, the shader with the “direction” and “directiono” inputs is getting applied to a mesh that doesn’t have those shader inputs. But your code looks right. I can imagine two possibilities - one is that there’s a bug in Panda3D, and the other is that somewhere in your scene is something that’s triggering that tag-state without supplying the necessary shader inputs.

I wish that error message contained more information - like the name of the node that’s triggering the error. Unfortunately, the error is coming from deep inside a module that doesn’t have access to that information.

I’d like to write a recursive routine to walk your scene graph, searching for the exact node that generated the error. But the problem is - I know how to say nodepath.getNetState. What I don’t know is how to get the net state including the tag state and initial state of a given camera. Without that, this isn’t going to be very useful. I need panda3d to compose the tag state in, and I need it to do it the exact same way it will do it during cull.

David - is there any way to do this?

I forgot to write the most important thing:

The “shadowshader” used in shadow_mapping needs the shaderInput ‘direction’ and ‘directiono’ from the “standard” shader.

Problem: Since the inputs are mesh-dependants, the “switch” class isn’t able to get them.

What I want to do :

1)In the mesh creation, I stock the shader input “direction” and “directiono”, and they work for their shader (mesh.sha)

2 )I switch the shaderAttrib to activate my shadow mapping.
I create a new shaderAttrib, but i still need the old “direction” and “directiono” input.
What I want to do is when I execute ShaderAttib.make(), I’m able to get back a shaderattrib with the previous inputs.

Any ideas on how I can do that?

I wouldn’t expect the tag-state to replace the existing state - I would expect it to be composed with the existing state. That would tend to leave the shaderinputs there. But maybe I’m wrong about the behavior?

I’m sure David knows.

The tag state read from the camera is composed with the existing state, as if it had been applied to render (or, strictly speaking, to an imaginary node above render). Josh is right, this shouldn’t disturb the shader inputs unless you specifically set them off in the tag state.

Getting the net state including the camera’s tag state isn’t difficult. The algorithm is simple: look up the state corresponding to a node’s tag value, and compose the result on top of the node’s net state from the scene graph. This function implements this behavior, exactly the same way Panda does during the cull traversal:

def getNetTagState(nodePath, camera):
    """ Returns the net state of the NodePath as seen by the indicated
    camera, accounting for any TagStates applied to the camera.
    Camera should be a NodePath to a camera, e.g. base.cam."""

    state = nodePath.getNetState()
    key = camera.node().getTagStateKey()
    tagState = camera.node().getTagState(nodePath.getNetTag(key))
    return tagState.compose(state)

With a function like this, it is easy to search recursively for a node lacking the shader attributes.

Also be sure to consider the traversal by other cameras in the scene, if any. A shadow camera, for instance?

David

I’m not sure i fully understand what is going on here.

so.
I have a scene working perfectly, with shader

on press of a button, i activate a shadow cam, and switch the meshs olds shaders attributes ( that haven’t been created explicitly ) to their new one. and there, i crash.

If the tagstate doesn’t overlap my old state as you said, i shouldn’t have a shaderinput problem, should i ? i still thinking the main problem is that i wanted to use some shaderInput put in the node with the new shader, but as i put i fresh shaderstate i erase the old one.

Are you implying that my shader input problem comes from my shadow cam and it’s shaders ?

my shadow cam:

self.LCam=base.makeCamera(self.buffer)
self.LCam.reparentTo(spotholder)
lens = OrthographicLens()
lens.setFilmSize(lens_l,lens_h )
lens.setNearFar(near,far)
self.LCam.node().setLens(lens)

shadowCastershader = loader.loadShader(('shader/shadow_caster.sha'))
myShaderAttrib = ShaderAttrib.make()
myShaderAttrib = myShaderAttrib.setShader(shadowCastershader)
my_state = render.getState().addAttrib(myShaderAttrib)
self.LCam.node().setInitialState(my_state)

should i , and if how, deactivate all my shader for the shadow cam since i only care about distance ?

my meshs doen’t use a named shaderattrib, ( i just put shaderInput in their node as you 've seen. should i make one ? )

Wait, I’m confused now. This function only considers the tag of the scene graph leaf node. Are the tags of interior nodes ignored?

SylHar - like I said, your code looks right. I have no idea where the problem is coming from. I’m just using a relatively brute force debugging strategy — find the node that triggers the problem, and maybe when we look closer at that node, we’ll notice something we didn’t notice before.

No, it doesn’t. It calls getNetTag(), which returns the value of the tag as inherited from any ancestor node.

David

ok i found the bug !

i have just put the tag on a parent node by mistake.
every thing fine now
thank you.

Wait, I don’t understand. You mean the “material_type” tag was applied to a node which was a parent of your mesh node, instead of the mesh node itself? But that should work just as well. If it didn’t, it’s a bug.

Can you tell us more about that?

David

well, that’s assign a shader to a node that doesn’t have the corresponding shaderInput .
( it’s only a nodePath with no other child that the mesh )

node = NodePath(...)
node.setTag()
mesh.setShaderInput(...)
mesh.reparentTo(node)
mesh.setTag()

Clearing this tag has solved the problem,… but it’s possible it’s bug.

Ah, I’d thought you’d bound the shaderInput into the same tag that applies the shader. That way, it would be impossible to apply the shader without also applying the shaderInput at the same time.

If you didn’t do it this way, and you do have a node to which you bound the shader without also applying the shaderInput, then it’s not a Panda bug.

David