Cloning a Material doesn't work

I’ve tried to subclass a THREE.StandardMaterial

//something like this not all the code
class BwMaterial extends THREE.StandardMaterial{
 constructor(parameters){
   super(parameters)
   this.onBeforeCompile = shader=>{
     shader.uniforms.uBWActive = {value: 0}
     shader.fragmentShader = 'uniform float uBWActive;\n' + shader.fragmentShader
     shader.fragmentShader = shader.fragmentShader.replace('}$', 'if(uBWActive == 1) { gl_FragColor.xyz = dot(vec3(1.),gl_FragColor.xyz);\n} }\n')
   }
 }
 toggleBW(){
   const { uBW } = this.userData.uniforms
   uBW.value = uBW.value ? 0 : 1
 }

The idea is to extends the StandardMaterial with a flag that would override the color output with grayscale output. So i’m trying to use this:

https://threejs.org/docs/#api/materials/Material.onBeforeCompile

An optional callback that is executed immediately before the shader program is compiled. This function is called with the shader source code as a parameter. Useful for the modification of built-in materials.

So i am trying to modify a built in material.

myModifiedBuiltInMaterial = new BWMaterial({color:'red'})
//renders red

myModifiedBuiltInMaterial.toggleBW() 
//renders grayscale

myCloneMaterial = myModifiedBuiltInMaterial.clone()

myCloneMaterial.color.set(0x00ff00)

//renders blue
myCloneMaterial.toggleBW()

//still renders blue

What am i doing wrong here? I would like to make a modified material and then be able to clone it.

Is this an invalid pattern, what would be three.js’s opinions on how to do this. I like subclassing Material and Mesh and such, but it doesn’t seem to like me doing this.

I’m confused with how .clone() is supposed to work.

In computer science, cloning refers to the making of an exact copy of an object,

But this clone doesn’t seem to make an exact copy of an object.

1 Like