How to set custom attribute on ShaderMaterial for use with instances and clones at the same time?

Hi,
I have a custom shader for my ShaderMaterial, and want to be able to use that material on meshes that are instanced, but also on simple clones. For that material I need to set some parameters, that are unique to each instance/clone.
Here’s an example:
https://playground.babylonjs.com/#026IT4
When using instances everything works as expected (with instancedBuffers and a shader attribute), but how can I set the same attribute for the normal mesh, when no instances are used? (and with the same shader code)
If you set useInstances=false, the meshes are just black (or invisible on another pc).
I don’t know that much about shaders/vertex buffers, so maybe I’m missing something here.
Thanks :slight_smile:

It can’t really work with clones because clones share the same geometry. So, setting a customColor attribute on the sphere will make sphereClone use the same custom colors.

Apart from that, in the “clone” case, you must provide a value for customColor for each vertex of the mesh and not a single color as in the “instance” case:

https://playground.babylonjs.com/#026IT4#1

As explained, geometry (so attributes) are shared for both spheres, that’s why both spheres are green.

Ok thanks, so there is no good way to accomplish this? Before I just used uniforms in the shader code and shaderMaterial.setVector3(…) for the clones, but that doesn’t work for instances with unqiue values for each one.
Should I just use two different shaders for instances and clones then?

I think so, and that would consume less memory as you will only have to pass a single color to the shader instead of a buffer attribute:

Note that the shader code is the same because you can use #ifdef INSTANCES to differentiate both cases.

2 Likes

Ahh, cool, that’s what I was looking for, thanks again :slight_smile:

I’ve got another question, if anyone is still reading here:
How can I set a single float value when using instancedBuffers?
for example, I want to set “let test: number = 5” to the instanced buffer:
mesh.registerInstancedBuffers(“num”, 1);
mesh.instancedBuffer[“num”] = ???

If you need a single value common for the entire shader, why not relying on a uniform instead ?

It’s a little convoluted because you must pass an object that has either a toArray or copyToArray method for the value when doing mesh.instancedBuffer["num"] = value, and obviously the float type does not have any of these methods:

https://playground.babylonjs.com/#026IT4#3

1 Like