InstancedMesh doesn't work with joined-mesh models

Hello. I created a .glb model (in Blender) which I want to subject to instancing just to make lots of copies. My model consists of many meshes so I joined them into one mesh (using Ctrl+J). There’s are neither materials assigned, nor modifiers. What I have noticed when added instantiated model to the Three.js scene is that it became distorted and flattened. Please take a look at my original example and the model subjected to instancing:

Original model:

Three.js:

I’ve read somewhere that there’s a problem with adding joined mesh as InstancedMesh to the scene. And there’s always a problem with joined-mesh model being distorted as seen above. Semms like setMatrix doesn’t work here.

Didi you happen to deal with such case? I mean use InstancedMesh with joined mesh? If so how did you solve the problem?

Here’s main part of code:

<template>
  <div id="viewport" ref="container"></div>
</template>

<script>
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'

export default {
  name: 'Scene',

  data() {
    return {
      camera: null,
      scene: null,
      renderer: null,
      light: null,
      light2: null,
      mesh: null,
      regalMesh: null
    }
  },
  methods: {
    init() {
       // .. some initial code

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

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

        let dummy = new THREE.Object3D();
        let amount = 1;

        // INSTANCING
        modelLoader.load(
            "Monkey.glb", (gltf) => {

        const _regalMesh = gltf.scene.getObjectByName('testMesh');
        const regalGeometry = _regalMesh.geometry.clone();
        const regalMaterial = _regalMesh.material;
        this.regalMesh = new THREE.InstancedMesh( regalGeometry, regalMaterial, amount );

               for (let i = 0; i <= amount; i++) {
                  dummy.position.set(i, 1, 1);
                  dummy.updateMatrix();
                this.regalMesh.setMatrixAt( i, dummy.matrix ); 
                }
              this.regalMesh.instanceMatrix.needsUpdate = true;
              this.regalMesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage );
                 this.scene.add(this.regalMesh);
            },
            // 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);
            }
        );             

    },

}
</script>

Check how looks model in three.js without inctancing

It looks ok but it’s not a case. I must use instancing. And don’t know how to solve my problem.

Can u share model Monkey.glb

Sure, here you are
test.glb (18.6 KB)

Your original model has changed scale and position, maybe is issue
image

I made an experiment. I first added original model and checked scale & position, then loaded InstancedMesh model and checked these params as well. Conclusion - they are exactly the same values. So I guess it’s not an issue here.

You can add that scale to instance matrix maybe
Your model have changed scale. If not apply that scale to instance, then model will be thin.
In instance you get geometry, but without scale that why thin

image

dummy.position.set(i, 1, 1);
dummy.scale.set(0.40804100036621094,1,5.016720294952393);
dummy.updateMatrix();
1 Like

It’s interesting. I logged both models in console and see scale is the same for both. In Blender it looks different. However, I applied transformation matrix which scales model. I finally was able to make it looks close to original. I used this code:

const defaultTransform = new THREE.Matrix4()
	.multiply( new THREE.Matrix4().makeScale( 0.4, 0.7, 5 ) );

monkeyGeometry.applyMatrix4( defaultTransform );

The issue is that I have no idea how to set proper scale values. I set above values just through ‘trial and error’ method. This is my outcome:

obraz

I see you applied scale on dummy. So I applied your code:

dummy.scale.set(0.40804100036621094,1,5.016720294952393);

and it works fine. Model looks like original one. However, when I use same values in transformation matrix:

.multiply( new THREE.Matrix4().makeScale(0.40804100036621094, 5.016720294952393, 1) );

then my model is still distorted. Why same scale values doesn’t work in transformation matrix?

Works good. Dummy matrix and applyMatrix4
image

Applied code:

const defaultTransform = new THREE.Matrix4().multiply( new THREE.Matrix4().makeScale(0.40804100036621094,1,5.016720294952393) );
_regalMesh.geometry.applyMatrix4( defaultTransform );

1 Like

It works well, thank you for your kind support. It’s clever solution!

1 Like

You can try export model from three.js to blender if need in it.

Later on, I would need to export models from Three.js (web app I create) and save them as .glb/.gltf as the final user could open the model in some browser/Paint3D. But it’s for the future.