NodeMaterial: how to efficiently set per-mesh value?

Having a node material with a InputBlock with value, but want to have different value for different mesh. Tried to use onBeforeRenderObservable for each mesh, but it won’t work unless something like markAsDirty or scene._cachedEffect = null or _drawWrapper._forceRebindOnNextCall = true. All of these seems to hurt performence, is there a more efficiently to set per-mesh value for NodeMaterial?

Here is my playground:

I’ve made a benchmark to compare different impl (42 fps on my laptop):

And cloning the material (38 fps on my laptop):

Hello :slight_smile:

For example in your case you can use the mesh.instanceColor from NME

Then after loading your node material, you can modify the color :

box1.instancedBuffers.instanceColor = new BABYLON.Color4(row / rows, col / cols, 0, 1);

Playground

++
Tricotou

1 Like

Thanks for this, instancing makes excellent performance compared to meshes, but this playground is only to show the case of changing value for each mesh. In real cases, the meshes can have different vertex attributes so can be rendered as instances. Also, color is the most common property to make an example, but sometimes I want to change more than colors, maybe something like the speed of wave.

Maybe have a look for example at this post where Popov is explaining that you can as well register some custom attributes

1 Like

That’s great, thanks. So the only thing keeping me from this is to render meshes with different vertex attributes (box and sphere for example) as instances.

You mean setting the same material on different meshes (sphere and box) which are not instances of the same original mesh ?

1 Like

Yes, different meshes with the same material, and wanted some value to change for different mesh (like the world matrix)

It’s not a problem to set a different attributes on each mesh, even if not an instance. In fact each mesh is somehow an instance of itself…

Have a look : Playground
Only fresh and unique meshes, no instances

1 Like

Thanks for that, but is it required to use color4? Do I have to align all other values I wanted to define as per-mesh by 4 floats?
Does not work for color3:

Works with color4:

Also, this example shows even worse performance (~18fps) compared to the example on main thread , which is ~42fps

Theorically you can use whatever you want. Directly from the NodeMaterialEditor, I don’t know (Maybe it would be a nice feature to be added : an instanceFloat node, to be used as unique float input per mesh/instance).

But to give you a GLSL example :

  • HERE is a GLSL version of the previous Playground
  • HERE- is the same but adding a new attribute customValue, working exactly the same as the instanceColor in term of binding :
// Custom Color
mesh.registerInstancedBuffer("instanceColor", 4);
mesh.instancedBuffers.instanceColor = new BABYLON.Color4(row / rows, col / cols, 0, 1);

// Custom Value
mesh.registerInstancedBuffer("customValue", 1);
mesh.instancedBuffers.customValue = (Math.random()>0.5);

To me it’s not due to the material setup. Even by removing all the lines about material (sticking to default mat), I’m running very low FPS as well. Seeing 10 000 meshes in the same viewport is very bad for performances and use to be avoidable (instanciating, etc)