Material material.onBeforeCompile problem for three.js



Material material.onBeforeCompile problem for three.js. When the transparency is set to true, the onBeforeCompile function will be executed twice, as shown in Figure 2, causing the inner function to execute twice, generating two shaders, the problem is that when I update the shader, I need to put the shader of both times into the array, and update at the same time, there is an uncontrollable problem, how to solve it?

Materials are cached and reused from the memory by their name. So you’re modifying all MeshBasicMaterials at the moment. To create a separate copy of the material, assign a different cache key to it:

material.customProgramCacheKey = () => `custom-${Math.random()}`;

If I add this it will execute this function infinitely, print infinitely, in fact I want to explain that when I set transparency to a material, it will call the onBeforeCompile function twice, when I don’t set transparency, it will only call the onBeforeCompile function once, and when I want to set transparent, I will only call the onBeforeCompile function once

That sounds like you’re creating a new material on every frame or in some loop.

No, adding your line of code will call the onBeforeCompile function indefinitely, setting the material transparency will call onBeforeCompile twice, and if you do not set transparency without adding your code, you will only call onBeforeCompil once. The version of the three.js is 144

Here in line 55 you can see an example of how to extend built-in materials, MeshStandardMaterial in this case (just be sure to do that separately from creating objects in the scene, and away from the render loop :sweat_smile::pray:)


Why does it execute 3 times

Because I was lazy, and instead of caching the material once, shaderMaterial() is called three times. It should be enough to place the material a few lines above in a variable, and then clone / assign it:

const material = shaderMaterial(); // NOTE This creates a new material, not just a new instance of an existing material

new Mesh(geometry, material);
new Mesh(geometry, material);
new Mesh(geometry, material);

Then it should be ok.


I just turned on transparency, why did it execute so many times, how to turn on transparency, still keep it 3 times

Oh, turning on the transparency indeed does slow down the entire scene significantly. Seems like transparent materials keep running onBeforeCompile over and over again - could be a bug? :eyes: (cc @Mugen87 )

1 Like

Double sided, transparent materials are rendered in two passes. Hence, the callback is executed twice. You can prevent this by setting the forceSinglePass material property to true (false is the default).

2 Likes

Just tried it, modifying the side attribute to single-sided, is valid. Setting forceSinglePasst has no effect

It should definitely prevent the double-pass rendering. Here is the respective code in the renderer:

You might want to debug this section in your application to make sure you don’t end up in the if statement.


Got it, I used version 144. What version started adding this code?

forceSinglePass was introduced with r149.