THREE Instancing


Basics

There aren't many documentations about THREE js instancing and the official documentation may be hard to understand for many. In this tutorial I will explain how to make an effective instancing class to make scene creation easier.

Explanation

If you have 2 models loaded into your scene each model uses one draw call to be shown on your screen. If those models are the same then you could use something like instancing which draws all models in one draw call. Drawing 2 models is fine but when you have to draw 10000 tree models that is a pain in the ass. (This is a massive simplification. I will not explain the whole instancing but rather show you how can you achieve something like this.)


Implementation

function rotateMatrix2(matrix, rx, ry, rz) {
  const rotation = new THREE.Euler(rx, ry, rz);
  matrix.multiply(new THREE.Matrix4().makeRotationFromEuler(
rotation));
}
class Imesh {
  constructor(x,y,z,modelPath='./models/tree1.glb',insnum=10) {
    const imessh = this;
    this.position = new THREE.Vector3(x, y, z);
    this.rotation = [0,0,0];
    this.meshes = [];
    this.matr = new THREE.Matrix4();
    this.inum = insnum;
    this.imcount = 0;
    gltfloader.load( modelPath, function (gltf) {
      gltf.scene.traverse(function (child) {
        if (child.isMesh) {
          const instancedMesh = new THREE.InstancedMesh
( child.geometry, child.material, imessh.inum );
          imessh.meshes.push(instancedMesh);
          scene.add( instancedMesh );
        }
      });
    });
  }
  setPosition(x, y, z) {
    this.position.set(x, y, z);
  }
  setRotation(x, y, z) {
    this.rotation[0] = x;
    this.rotation[1] = y;
    this.rotation[2] = z;
  }
  createInstance() {
    for(let i = 0; i < this.meshes.length; i++){
      this.matr = new THREE.Matrix4();
      this.matr.setPosition(this.position);
      rotateMatrix2(this.matr,this.rotation[0],this.rotation[1],
this.rotation[2]);
      this.meshes[i].setMatrixAt(this.imcount, this.matr);
    }
    this.imcount++;
  } }



How to use class?

Assuming you have a scene named "scene" and a GLTFLoader named "gltfloader":
1. Create an Imesh variable:


const meshpopulator = new Imesh(x,y,z,'path/to/your/model.glb',10/*Number Of Instances*/);


2. Set the position and the rotation of the next instance.


meshpopulator.setPosition(0,1,1);
meshpopulator.setRotation(Math.PI/2,0,0);

3. Create the instance:


meshpopulator.createInstance();

Go back to main page