Share Three.js Materials Across Multiple Meshes
In Three.js, creating a new material for every individual mesh can quickly exhaust GPU memory and degrade rendering performance. This article explains how to optimize your WebGL applications by sharing a single material instance across multiple meshes, thereby reducing memory usage, minimizing draw calls, and streamlining performance.
The Concept of Shared Materials
By default, every time you instantiate a material using
new THREE.MeshStandardMaterial() (or any other material
class), Three.js allocates memory for that material and compiles a
shader program on the GPU.
If you have hundreds of objects that look identical—or even objects that share the same texture but have different shapes—you do not need to create a new material for each one. Instead, you can define the material once and pass its reference to multiple mesh constructors.
How to Implement Shared Materials
To share a material, instantiate it once and pass the same variable
to every THREE.Mesh you create.
import * as THREE from 'three';
// 1. Create the geometries
const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
const sphereGeometry = new THREE.SphereGeometry(0.5, 32, 32);
// 2. Create a single material instance
const sharedMaterial = new THREE.MeshStandardMaterial({
color: 0xff0000,
roughness: 0.4,
metalness: 0.2
});
// 3. Create multiple meshes using the same material reference
const boxMesh = new THREE.Mesh(boxGeometry, sharedMaterial);
const sphereMesh = new THREE.Mesh(sphereGeometry, sharedMaterial);
// Position the meshes
boxMesh.position.x = -2;
sphereMesh.position.x = 2;
// 4. Add them to the scene
scene.add(boxMesh);
scene.add(sphereMesh);In this example, both the box and the sphere share the exact same material. The GPU only compiles the shader and uploads the material properties once, significantly reducing the memory footprint.
Key Considerations When Sharing Materials
While sharing materials is highly efficient, there are important behaviors to keep in mind:
1. Global Property Changes
Because the meshes share a single reference, modifying any property on the material will instantly affect all meshes using it.
// This will turn BOTH the box and the sphere blue
sharedMaterial.color.setHex(0x0000ff);2. Handling Slight Variations (Colors)
If you need meshes to share the same material properties (like roughness, metalness, and maps) but have different colors, you can use vertex colors instead of creating multiple materials.
- Enable vertex colors on your geometries.
- Set
vertexColors: trueon your shared material.
3. Scaling with InstancedMesh
If your meshes share both the same geometry and the same material, do
not use individual THREE.Mesh objects. Instead, use
THREE.InstancedMesh. This class allows you to render
thousands of identical objects with a single draw call, maximizing both
CPU and GPU performance.
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(boxGeometry, sharedMaterial, count);
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(Math.random() * 10, Math.random() * 10, Math.random() * 10);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(instancedMesh);