# Material material.onBeforeCompile problem for three.js

**URL:** <https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340>\
**Category:** Questions\
**Tags:** materials\
**Created:** [June 29, 2023, 3:13am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340 "2023-06-29T03:13:14Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![wenrenqiang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/wenrenqiang/32/54020_2.png) [@wenrenqiang](https://discourse.threejs.org/u/wenrenqiang)\
**Post date:** [June 29, 2023, 3:13am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/1 "2023-06-29T03:13:15Z")

</div>

![1688007881003](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/a/f/af94b53b3cdcf779919a783db658c0bf053dfbb9.png)  
 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/e/8/e80bde55f9748ff887a8e9e08f49a6e890561d3a.png)  
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?

---

<div class="post-metadata">

**Author:** ![mjurczyk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mjurczyk/32/10995_2.png) [@mjurczyk](https://discourse.threejs.org/u/mjurczyk)\
**Post date:** [June 29, 2023, 4:13am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/2 "2023-06-29T04:13:21Z")

</div>

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:

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

```

---

<div class="post-metadata">

**Author:** ![wenrenqiang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/wenrenqiang/32/54020_2.png) [@wenrenqiang](https://discourse.threejs.org/u/wenrenqiang)\
**Post date:** [June 29, 2023, 7:18am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/3 "2023-06-29T07:18:47Z")

</div>

![1688023052757](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/0/d/0d95d0ca5af89602d528f3f71dafea21ffea77a9.png)

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

---

<div class="post-metadata">

**Author:** ![mjurczyk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mjurczyk/32/10995_2.png) [@mjurczyk](https://discourse.threejs.org/u/mjurczyk)\
**Post date:** [June 29, 2023, 7:24am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/4 "2023-06-29T07:24:51Z")

</div>

> [@wenrenqiang](#):
>
> If I add this it will execute this function infinitely

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

---

<div class="post-metadata">

**Author:** ![wenrenqiang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/wenrenqiang/32/54020_2.png) [@wenrenqiang](https://discourse.threejs.org/u/wenrenqiang)\
**Post date:** [June 29, 2023, 7:29am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/5 "2023-06-29T07:29:58Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![mjurczyk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mjurczyk/32/10995_2.png) [@mjurczyk](https://discourse.threejs.org/u/mjurczyk)\
**Post date:** [June 29, 2023, 7:42am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/6 "2023-06-29T07:42:12Z")

</div>

[Here](https://codepen.io/mjurczyk/pen/rNqYObN) 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 😅🙏)

---

<div class="post-metadata">

**Author:** ![wenrenqiang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/wenrenqiang/32/54020_2.png) [@wenrenqiang](https://discourse.threejs.org/u/wenrenqiang)\
**Post date:** [June 29, 2023, 8:00am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/7 "2023-06-29T08:00:29Z")

</div>

![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/6/c6276f5c5bd700d494d2e76015ae8e7c5af09aa7.png)  
Why does it execute 3 times

---

<div class="post-metadata">

**Author:** ![mjurczyk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mjurczyk/32/10995_2.png) [@mjurczyk](https://discourse.threejs.org/u/mjurczyk)\
**Post date:** [June 29, 2023, 8:16am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/8 "2023-06-29T08:16:50Z")

</div>

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:

```js
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.

---

<div class="post-metadata">

**Author:** ![wenrenqiang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/wenrenqiang/32/54020_2.png) [@wenrenqiang](https://discourse.threejs.org/u/wenrenqiang)\
**Post date:** [June 29, 2023, 8:48am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/9 "2023-06-29T08:48:30Z")

</div>

![1688028470210](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/3/6/36959fd92e64ea028db33421a1d3962a5ed33580.png)  
I just turned on transparency, why did it execute so many times, how to turn on transparency, still keep it 3 times

---

<div class="post-metadata">

**Author:** ![mjurczyk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mjurczyk/32/10995_2.png) [@mjurczyk](https://discourse.threejs.org/u/mjurczyk)\
**Post date:** [June 29, 2023, 9:00am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/10 "2023-06-29T09:00:16Z")

</div>

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? 👀 (cc @Mugen87 )

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [June 29, 2023, 9:09am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/11 "2023-06-29T09:09:26Z")

</div>

> [@wenrenqiang](#):
>
> 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,

_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).

---

<div class="post-metadata">

**Author:** ![wenrenqiang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/wenrenqiang/32/54020_2.png) [@wenrenqiang](https://discourse.threejs.org/u/wenrenqiang)\
**Post date:** [June 29, 2023, 9:21am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/12 "2023-06-29T09:21:14Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [June 29, 2023, 9:24am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/13 "2023-06-29T09:24:08Z")

</div>

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

> <https://github.com/mrdoob/three.js/blob/edefdc237b2528b9668fb873a1c06cb835840303/src/renderers/WebGLRenderer.js#L1461-L1477>

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

---

<div class="post-metadata">

**Author:** ![wenrenqiang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/wenrenqiang/32/54020_2.png) [@wenrenqiang](https://discourse.threejs.org/u/wenrenqiang)\
**Post date:** [June 29, 2023, 9:31am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/14 "2023-06-29T09:31:42Z")

</div>

![1688031054522](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/0/3/0365fc9cd848213972e6d493e890d3d358e108c2.png)  
Got it, I used version 144. What version started adding this code?

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [June 29, 2023, 10:24am UTC](https://discourse.threejs.org/t/material-material-onbeforecompile-problem-for-three-js/53340/15 "2023-06-29T10:24:04Z")

</div>

`forceSinglePass` was introduced with `r149`.
