Clone a ShaderMaterial and Have Different Uniforms for Different Copies of the Material

Here’s a basic demo of a little something that I recently discovered and thought was pretty neat.

You can clone a shader material and have different sets of uniforms for different copies of the material.

In the following simple scene, the planes share the same material but have different uniforms which results in a different color for each plane:

https://jsfiddle.net/emcn0fbq/

If you didn’t know about this either, I hope you find this little tip as useful as I have :slight_smile:

const mesh2 = new THREE.Mesh(geometry, material.clone());

You’re cloning the material, they also by default have a custom set of uniforms as they are cloned too when cloning a ShaderMaterial.

You might be interested in this plugin i made for that purpose, to use a single material instance but use different uniform values on the fly derived from the mesh for instance. It saves you from cloning materials and all their properties just to change some parameters.

Recently also added a concept for shader code sharing to avoid having a copy of the shader string of every cloned ShaderMaterial, gonna add it in the next release. It essentially makes ShaderMaterials more lightweight like using in-built materials.

2 Likes

Ooh, very cool! Thanks for sharing. I’ve bookmarked your post for future reference.

My post was derived from the docs on shaderMaterial here:

https://threejs.org/docs/index.html#api/en/materials/ShaderMaterial.clone

I did a double take when I read about the clone method there, cause I’ve never seen anybody utilise it before with ShaderMaterial and so thought it was worth highlighting with an example.

1 Like

I’ve got to ask, what exactly is this achieving? If you’re not cloning any of the uniforms you might as well just construct new instances? Or do something like

const props = {
  vertexShhader,
  fragmentShader,
  side
}

const matA = new ShaderMaterial({...props, uniforms: uniformsA})
const matB = new ShaderMaterial({...props, uniforms: uniformsB})
const matC = new ShaderMaterial({...props, uniforms: uniformsC})