How to make InstancedMesh working with BufferGeometry?

Hello there. I imported .glb model created in Blender. Now I want to make many copies of the model using InstancedMesh. There’s a method I follow to do that - I extract geometry and material from my model, then make BufferGeometry and finally create a new Mesh. At the end I apply instancing to newly created Mesh. So it all seems standard procedure but the issue is that model doesn’t show up on the scene. I don’t have any errors, just no model on the scene. What’s wrong with my code or (maybe) model?

        // DRACOLoader
        const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath('dracoDecoder/');

        // GLTFLoader
        const modelLoader = new GLTFLoader();
        modelLoader.setDRACOLoader(dracoLoader);

        modelLoader.load(
            "regalFrontBottomNoMaterials.glb", (gltf) => {

              const regal = gltf.scene.getObjectByName('regalMesh');
              const meshes = [];

              regal.traverse(function (mesh, index) {
                if (mesh.geometry != undefined && mesh.geometry != null) {
                  meshes.push(mesh);
                }
              });

              if (regal.name.includes('regalMesh') || (regal.userData.InstancedObjects != undefined && regal.userData.InstancedObjects != null)) {
                
                var materials = [];
                var geometries = [];
                var mergedGeometry = new THREE.BufferGeometry();
                var meshMaterial;
                var mergedMesh;

                meshes.forEach(function (mesh, index) {
                  mesh.updateMatrix();

                  var geo = mesh.geometry.clone().applyMatrix4(mesh.matrix);
                  geometries.push(geo);

                  meshMaterial = mesh.material.clone();
                  materials.push(meshMaterial);               

                });

                try {
                  mergedGeometry = mergeBufferGeometries(geometries, true);
                  mergedGeometry.groupsNeedUpdate = true;
                  
                } catch (e) {
                  console.log(regal.name)
                }

                mergedMesh = new THREE.Mesh(mergedGeometry, materials);
                var count = 2;

                  mergedMesh.geometry.center()
                  var instanceMesh = new THREE.InstancedMesh(mergedMesh.geometry, mergedMesh.material, count)
                  instanceMesh.name = regal.name;
                  instanceMesh.userData = regal.userData;
                  scene.add(instanceMesh)
              }
              
              console.log(mergedMesh)

            },
            // called while loading is progressing
            function (xhr) {
            console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
            
            },
            // called when loading has errors
            function (error) {
            console.log(error);
            }
        );  

regalFrontBottomNoMaterials.glb (327.3 KB)

      for (let i = 0; i < count ; i++) {

        const matrix = new THREE.Matrix4()
        instanceMesh.setMatrixAt(i, matrix);

      }

It seems that the matrix of each mesh needs to be set.

1 Like

Could you please show me your whole code? I did something like that before but had issues with scaling, I can see at least scale is ok in your case.

		const randomizeMatrix = function () {

			const position = new THREE.Vector3();
			const rotation = new THREE.Euler();
			const quaternion = new THREE.Quaternion();
			const scale = new THREE.Vector3();

			return function ( matrix ) {

				position.x = Math.random() * 40 - 20;
				position.y = Math.random() * 40 - 20;
				position.z = Math.random() * 40 - 20;

				rotation.x = Math.random() * 2 * Math.PI;
				rotation.y = Math.random() * 2 * Math.PI;
				rotation.z = Math.random() * 2 * Math.PI;

				quaternion.setFromEuler( rotation );

				scale.x = scale.y = scale.z = Math.random() * 1;

				matrix.compose( position, quaternion, scale );

			};

		}();
      const matrix = new THREE.Matrix4();
      for (let i = 0; i < count; i++) {

        randomizeMatrix(matrix);
        instanceMesh.setMatrixAt(i, matrix);

      }

You can learn from this example to set the matrix. In the above code, I use the method of randomly generating the matrix in this example.

Thank you buddy

You’re welcome. :beer:

1 Like