Node Material Cannot Set Value On Defines

We started seeing a strange error in version 5.0.0-alpha.60 (sorry we’re stuck on this version a little while longer)

I’m looking in the Babylon code but I don’t understand what would cause a Node Material to not have a defines object available. What’s worse is that this is an intermittent problem doesn’t happen all the time. The material JSON loads ok, builds ok, but then fails when attempting to set a texture block with a texture loaded texture.

 const textureBlock = nodeMaterial.getBlockByName(blockName) as TextureBlock;
  if (texture && textureBlock) {
    textureBlock.texture = texture;
  }

Is there a way to understand this error without a Playground?

   message: defines.setValue is not a function
       name: TypeError
       stack: TypeError: defines.setValue is not a function
    at TextureBlock3.initializeDefines (http://localhost:8080/scripts/client.js:164982:21)
    at http://localhost:8080/customization/client.js:162022:15
    at Array.forEach (<anonymous>)
    at NodeMaterial2._processDefines (http://localhost:8080/client.js:162021:46)
    at NodeMaterial2.isReadyForSubMesh (http://localhost:8080//client.js:162105:29)
    at Mesh7.render (http://localhost:8080/client.js:73644:29)
    at SubMesh2.render (http://localhost:8080/scripts/client.js:64298:31)
    at RenderingGroup2.renderSorted (http://localhost:8080/client.js:54209:21)
    at RenderingGroup2.renderTransparentSorted (http://localhost:8080/client.js:54182:34)
    at RenderingGroup2.render (http://localhost:8080/client.js:54162:20)

cc @Evgeni_Popov our NME expert

Actually the defines object does exist but according to the error message the setValue property is not a function (I don’t know how it is possible)…

That will be difficult to debug it without a repro. Just for testing purpose, are you able to use a newer version than 5.0.0-alpha.60?

1 Like

Yes, I can try that tomorrow and let you know what I see. Thanks!

Quick update here. Can you help me understand what the isReady and onBind events do for a material? Our use case here is that we are swapping from a PBRMaterial to a NodeMaterial but it’s possible we aren’t waiting long enough. Am I right that if we did (pseudo code)

createMaterial()
if (isReady)
mesh.material = material
material.onBind(do something here)

Then we can assume that everything is ready to be rendered?

Kind of like in this playground, only not using a Node Material.

Yes, if isReadyForSubMesh returns true, it means the material is ready to be rendered for this submesh.

material.onBindObservable will only be called when the mesh is rendered with the material: if the material is not ready, it won’t be called.

1 Like

I also notice there is an onBuildObservable and onCompileObservable for Node Materials. Could our error above be because we are attempting to set properties on the new material before the shader is fully compiled or built?

No, you can set properties on a material at any time. The error above is something that should not be possible, setValue should be a function. That’s why it’s going to be difficult to find the problem without a repro.

Have you been able to do that:

Just for testing purpose, are you able to use a newer version than 5.0.0-alpha.60?

It could be a bug we have fixed since then.

We updated to the latest code and are still seeing issues. The basic issue here seems to be that if you do the following operations, you see funny results when taking screenshots (ordinary render loop seems fine)

  1. Swap a PBR material for a Node Material
  2. Update texture blocks in NM
  3. Take a screenshot using render target texture
  4. Swap back to PBR material
  5. Repeat back and forth

Locally, this does not result in the defines error but the renders are inconsistent.

Are you able to setup a repro in the Playground? That would help a lot.

Also, something that you can try to do before/after step 3 is to call scene.resetDrawCache() and see if that helps.

2 Likes

Unfortunately this method does not exist in the alpha version we’re stuck on, but we were able to trick it by running a render twice with the first one being a 1x1. I’m guessing that this does some similar clearing of cache?

But a new wrinkle is that this error also seems to affect Dynamic Textures where this call fails:

https://github.dev/BabylonJS/Babylon.js/blob/327d5f43e9065daad8c2fa450035952727c8f818/packages/dev/core/src/Materials/Textures/dynamicTexture.ts#L150

It’s finding a null value for the engine. I’m guessing that there is just some race condition here that happens when we update and then immediately run the screenshot from render target textures. But since we’re on an older version (and alpha, to boot!) then I don’t think it’s really great to ask you folks to debug it. We’re going to work on updating the version and then see where that lands us.

2 Likes