Geometry > BufferGeometry does not group by materialIndex efficiently (reduce your draw calls by 1/4 with this one weird trick)

When a Geometry is converted to a BufferGeometry, the Faces of the Geometry are turned into BufferGeometry groups. Each group becomes a draw call in the end.

Faces are not grouped by .materialIndex, instead the faces are looped over and **a new group is created every time a different materialIndex is found:

if ( face.materialIndex !== materialIndex ) {
materialIndex = face.materialIndex;
if ( group !== undefined ) {
group.count = ( i * 3 ) group.start;
groups.push( group );
}
group = {
start: i * 3,
materialIndex: materialIndex
};
}
}

By sorting my Geometry’s faces (geometry.faces = geometry.faces.sort((a,b) => a.materialIndex - b.materialIndex)) I was able to reduce my BufferGeometry groups (and therefore draw calls) from 400 to 50.

You have to sort other things too to make sure all the data lines up.

There’s at least two ways to address this, sort the faces and all other geometry arrays first before converting, or make the groups loop actually group by materialIndex instead of building a new one every time it finds a new one.

Author: Fantashit

1 thought on “Geometry > BufferGeometry does not group by materialIndex efficiently (reduce your draw calls by 1/4 with this one weird trick)

  1. You can do this:

    geometry.sortFacesByMaterialIndex();
    bufferGeometry = new THREE.BufferGeometry().from( geometry );

Comments are closed.