ANSWER OUTDATED
The API for Threejs has undergone changes and no longer supports the old Geometry
interface. Now, you need to directly work with BufferGeometries and their attributes. Additional merging utilities can be found on the DOCS page: BufferGeometryUtils.
This issue arises due to BoxGeometry
(source) assigning a different MaterialIndex
to each of its faces. This determines which material will be applied to that face when using an array of materials.
To ensure that each geometry only uses the specified material in the array, you must reset the MaterialIndex
to 0
for every face of the geometry. This way, the geometry.merge()
function will accurately adjust each geometry to use the correct material.
I have updated your combine
function to handle this seamlessly. I couldn't find a better approach to resetting MaterialIndex
, at least not currently available.
function combine(meshes) {
let mergeGeometry = new THREE.Geometry();
for (let i = 0; i < meshes.length; i++) {
meshes[i].updateMatrix();
// update materialIndex
for ( let j = 0; j < meshes[i].geometry.faces.length; j++ ) {
meshes[i].geometry.faces[j].materialIndex = 0;
}
mergeGeometry.merge( meshes[i].geometry, meshes[i].matrix, i );
}
return mergeGeometry;
}
JSFiddle Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<style>
body {
margin: 0;
position: fixed;
}
canvas {
width: 100%;
height: 100%;
display: block;
}
</style>
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
let renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Scene
let scene = new THREE.Scene();
scene.background = new THREE.Color(0xcce0ff);
// Camera
let camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
1,
1000
);
camera.position.set(30, 0, 50);
let controls = new THREE.OrbitControls(camera);
// Geometry
let cube1Geometry = new THREE.BoxGeometry(10, 10, 10);
let cube2Geometry = new THREE.BoxGeometry(10, 15, 5);
// Material
let cube1Material = new THREE.MeshStandardMaterial({
color: 0x7c3c3c,
roughness: 1
});
let cube2Material = new THREE.MeshStandardMaterial({
color: 0x01b8ba,
roughness: 0.1
});
// Mesh
let cube1 = new THREE.Mesh(cube1Geometry, cube1Material);
let cube2 = new THREE.Mesh(cube2Geometry, cube2Material);
// Combine
let singleGeometry = combine([cube1, cube2]);
let single = new THREE.Mesh(singleGeometry, [
cube1Material,
cube2Material
]);
scene.add(single);
function combine(meshes) {
let mergeGeometry = new THREE.Geometry();
for (let i = 0; i < meshes.length; i++) {
meshes[i].updateMatrix();
// update materialIndex
for ( let j = 0; j < meshes[i].geometry.faces.length; j++ ) {
meshes[i].geometry.faces[j].materialIndex = 0;
}
mergeGeometry.merge( meshes[i].geometry, meshes[i].matrix, i );
}
return mergeGeometry;
}
// LIGHT
let light1 = new THREE.AmbientLight(0x666666);
scene.add(light1);
let light = new THREE.SpotLight(0xdfebff, 1);
light.position.set(50, 200, 100);
scene.add(light);
requestAnimationFrame(function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
});
</script>
</body>
</html>