function sortInstancedMesh( mesh, compareFn ) {

	// store copy of instanced attributes for lookups

	const instanceMatrixRef = deepCloneAttribute( mesh.instanceMatrix );
	const instanceColorRef = mesh.instanceColor ? deepCloneAttribute( mesh.instanceColor ) : null;

	const attributeRefs = new Map();

	for ( const name in mesh.geometry.attributes ) {

		const attribute = mesh.geometry.attributes[ name ];

		if ( attribute.isInstancedBufferAttribute ) {

			attributeRefs.set( attribute, deepCloneAttribute( attribute ) );

		}

	}


	// compute sort order

	const tokens = [];

	for ( let i = 0; i < mesh.count; i ++ ) tokens.push( i );

	tokens.sort( compareFn );


	// apply sort order

	for ( let i = 0; i < tokens.length; i ++ ) {

		const refIndex = tokens[ i ];

		_matrix.fromArray( instanceMatrixRef.array, refIndex * mesh.instanceMatrix.itemSize );
		_matrix.toArray( mesh.instanceMatrix.array, i * mesh.instanceMatrix.itemSize );

		if ( mesh.instanceColor ) {

			_color.fromArray( instanceColorRef.array, refIndex * mesh.instanceColor.itemSize );
			_color.toArray( mesh.instanceColor.array, i * mesh.instanceColor.itemSize );

		}

		for ( const name in mesh.geometry.attributes ) {

			const attribute = mesh.geometry.attributes[ name ];

			if ( attribute.isInstancedBufferAttribute ) {

				const attributeRef = attributeRefs.get( attribute );

				attribute.setX( i, attributeRef.getX( refIndex ) );
				if ( attribute.itemSize > 1 ) attribute.setY( i, attributeRef.getY( refIndex ) );
				if ( attribute.itemSize > 2 ) attribute.setZ( i, attributeRef.getZ( refIndex ) );
				if ( attribute.itemSize > 3 ) attribute.setW( i, attributeRef.getW( refIndex ) );

			}

		}

	}

}
Sorts the instances of the given instanced mesh.

@param {InstancedMesh} mesh - The instanced mesh to sort.
@param {function(number, number):number} compareFn - A custom compare function for the sort.