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.

2 Likes

You might give this plugin a try

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

1 Like

I’m facing the same request as the original post : I have hundreds of Points objects that share the same material but I would like to update one uniform value per Point object.

Do you have an example code for uniformsNeedUpdate and onBeforeRender() please ?

Yes, the Lensflare class uses the flag in its onBeforeRender() implementation.

1 Like

three.js always tries to determine if it’s possible to share shader programs across materials

Sorry for commenting an old post, but I was wondering: how does this work exactly?
PS: thanks for providing all these useful insights :slight_smile: