Assign many materials to single mesh gives immediate performance issues

Hi All, I’m new to three.js and the forum. I have a newbie question and it’s about the relationship between performance and materials.

What I want
I have some custom geometry with a lot of faces. From a selection of those faces, I would like to control the material (emissive value) independently for animation purposes. To achieve this effect, I imagine I would need to assign a different material to all faces I need separate control of.

First, I’m creating some custom geometry. This is what i’m doing:

// Irrelevant stuff above

geom.vertices.push(a); // 0
geom.vertices.push(b); // 1
geom.vertices.push(c); // 2
geom.vertices.push(d); // 3
geom.vertices.push(e); // 4
geom.vertices.push(f); // 5
geom.vertices.push(g); // 6
geom.vertices.push(h); // 7

let length = geom.vertices.length;

a = length - 8;
b = length - 7;
c = length - 6;
d = length - 5;
e = length - 4;
f = length - 3;
g = length - 2;
h = length - 1;

geom.faces.push(new THREE.Face3(c, b, a)); // [c, b, a]
geom.faces.push(new THREE.Face3(b, c, d)); // [b, c, d]

geom.faces.push(new THREE.Face3(d, e, b)); // [d, e, b]
geom.faces.push(new THREE.Face3(e, d, f)); // [e, d, f]

geom.faces.push(new THREE.Face3(f, g, e)); // [f, g, e]
geom.faces.push(new THREE.Face3(g, f, h)); // [g, f, h]

geom.faces.push(new THREE.Face3(h, a, g)); // [h, a, g]
geom.faces.push(new THREE.Face3(a, h, c)); // [a, h, c]

geom.faces.push(new THREE.Face3(h, d, c)); // TOP [h, d, c]
geom.faces.push(new THREE.Face3(d, h, f)); // TOP [d, h, f]

First, just to see if I can give all TOP faces a separate material, I do this:

let faceSelector = geom.faces.length - 1;
geom.faces[faceSelector].materialIndex = 1;
geom.faces[faceSelector-1].materialIndex = 1;

And then I create the mesh and materials as follows:

let materials = [
    new THREE.MeshStandardMaterial({
        color: 0x888888,
        metalness: 1,
        roughness: .4,
        envMap: reflectionCube,
        envMapIntensity: 1,
        wireframe: false
    }),
    new THREE.MeshStandardMaterial({
         color: 0x888888,
         wireframe: false,
         emissive: 0xffffff,
        emissiveIntensity: 1,
    })
];

this.object = new THREE.Mesh( geom, materials );

This works, the “top” faces have a different material now, but this seems to have an immediate performance impact and the framerate drops. But this isn’t even what I want. I want every top face to have a different material assigned instead of this, where all top faces have the same material assigned.

Am I doing something wrong? Is there a better way of achieving this or is having many materials on a single object inherently performance heavy and should I avoid it altogether?

Thanks!

That’s why it’s better to create a minimal, complete, and verifiable example.

Ah, sure I was trying to get this to work in jsbin and fiddle, but for some reason I can’t. I will see if I can do it differently.

Argh, I made a stupid assumption. I have assigned many materials and it hardly makes a difference. Thanks for the link to the minimal example explanation. Will do next time.

You need to call something like sortFacesByMaterialIndex on your geometry object. I’m not exactly sure what the function is called but it’s something along those lines. I’m currently not at my pc, so can’t check.

You call that function once after you’re done constructing the geometry.

Or maybe its on the mesh object. I’ll verify when I get home if you haven’t figured it out by then.

  • edit:

Verified it’s geometry.sortFacesByMaterialIndex();.
See the related issue on github here, notably the comment made by WestLangley at the bottom of the page: https://github.com/mrdoob/three.js/issues/7211