Sharing one material across multiple objects using onBeforeRender()

Title says it all - I want to set up one copy of MeshStandardMaterial and assign it to a number of objects, then let each object set its own color, textures, etc before being drawn. I figure this is a little tidier than doing all my setup for each and every material, as I’m injecting shader code like BPCEM and I worry that my myriad materials won’t share the same shader code unless I force them to.

Doesn’t seem to work!

What I’m seeing is every object with the material takes on the properties set by whichever one is drawn last (closest to the camera). My hunch is I’m probably misunderstanding the purpose of onBeforeRender(), and that it doesn’t work in-between draw calls because then the GPU would have to start drawing, stop drawing, start drawing, stop drawing, etc. If that’s the case, makes sense, all good.

But if what I’m trying to do is possible, can anyone point me in the right direction? Also, would this save performance vs one material per object?

What you are trying to do is not yet possible. At least with built-in materials. More details in this thread:

However, if you are using ShaderMaterial, it is possible via uniformsNeedUpdate to force a uniform update in onBeforeRender().

I’m not sure it’s worth to add this option for MeshStandardMaterial since the benefits are minor. three.js always tries to determine if it’s possible to share shader programs across materials. Because of this feature, you don’t save state changes by using uniformsNeedUpdate and thus don’t have a better performance. You only save a bit of RAM, that’s all.

1 Like

You might give this plugin a try

The uniforms per mesh part allows you to change uniforms for each mesh individually.

1 Like