How can I get InstancedMesh working properly with .glb?

I imported .glb file to my app, now I want to make copies of it using InstancedMesh. I followed this official example (I even used the same Flower.glb model): three.js/webgl_instancing_scatter.html at 191a1ef699a5d53de2cd645c667e7fee184a18fd · mrdoob/three.js · GitHub. I simplified my example, don’t need to to transform geometries, just need to make copies. I have no errors in the console so seems it works fine but the issue is that nothing shows up in the scene. I have no idea why, all the more that my example follows official Three.js example. What’s the issue?

<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'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

export default {
  name: 'Scene',

  data() {
    return {
      camera: null,
      scene: null,
      renderer: null,
      light: null,
      mesh: null,
      controls: null,
      width: 0,
      height: 0,
      stemMesh: null,
      blossomMesh: null
    }
  },

  methods: {
    init() {

        this.width = this.$el.offsetWidth
        this.height = this.$el.offsetHeight

        this.scene = new THREE.Scene();
        this.scene.background = new THREE.Color('#272727');

        this.camera = new THREE.PerspectiveCamera(70, this.width / this.height, 0.01, 100);
        this.camera.position.set(0,10,10);

        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setSize(this.width, this.height);
        this.$refs.container.appendChild(this.renderer.domElement);

        this.light = new THREE.DirectionalLight(0xffffff,2);
        this.light.position.set(1,1,1);
        this.scene.add(this.light);

        this.controls = new OrbitControls(this.camera, this.renderer.domElement);
        this.controls.update();

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

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

        // loading .glb model and make copies using InstancedMesh
        modelLoader.load(
            "Flower.glb", (gltf) => {

                const _stemMesh = gltf.scene.getObjectByName('Stem');
                const _blossomMesh = gltf.scene.getObjectByName('Blossom');

                const stemGeometry = _stemMesh.geometry.clone();
                const blossomGeometry = _blossomMesh.geometry.clone();

                const stemMaterial = _stemMesh.material;
                const blossomMaterial = _blossomMesh.material;

                this.stemMesh = new THREE.InstancedMesh( stemGeometry, stemMaterial, 20 );
                this.blossomMesh = new THREE.InstancedMesh( blossomGeometry, blossomMaterial, 20 );

                this.stemMesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage );
                this.blossomMesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage );

                this.scene.add(this.stemMesh);
                this.scene.add(this.blossomMesh);

                console.log(this.stemMesh)
            },

                function (xhr) {
                console.log((xhr.loaded / xhr.total) * 100 + "% loaded");      
            },

                function (error) {
                console.log(error);
            }
        );             

    },


    resizeCanvas() {

        this.width = this.$el.offsetWidth
        this.height = this.$el.offsetHeight

        this.camera.aspect = this.width / this.height
        this.camera.updateProjectionMatrix()

        this.renderer.setSize(this.width, this.height)
        this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
    },

    animate() {
        requestAnimationFrame(this.animate);
        this.controls.update();
        this.renderer.render(this.scene, this.camera);
    }

  },

    mounted() {
        this.init();
        this.animate();

        window.addEventListener('resize', () => {
        this.resizeCanvas();
      });
  }

}
</script>

Where do you set your new THREE.Matrix4()?
This part is missing (line 88 in the demo) you still need them, even if you keep all instances at the same position.

1 Like

I didn’t do that because I don’t want to make any transformations on my objects like resizing etc. That’s why I purposely removed this part of the code. However, I see it’s needed for some reason.

Why do I need to transform geometries? I don’t get it.

It’s like factory default values :wink:, it’s required by internal functions.
Sometimes new THREE. define multiples values at 0 under the hood for you

But some other times Three internal function expect you to provide your own zero/default values, they don’t check this for you.

1 Like

Ok, so it’s something what happens under the hood to make instancing working. Thank you, I’ll take a look into it and try to modify my code.