title: GLTF create instances
body: <p>I am new in THREEJS. In the past, I have used AFRAME, CESIUM, XEOGL and BABYLONJS. But eventually, due to memory consumption and performance, I have realized that the best product for making a CAD visualizer is THREEJS.</p>
  <p>BABYLONJS takes more than 4 minutes to load a big GLTF file (400MB) while THREEJS takes only 30 secs. The memory taken by BABYLONJS is 4 times that used by THREEJS.</p>
  <p>I know that there are still some issues to be able to create instances (GPU) from a loaded GLTF file in THREEJS, but I only need to change the position and rotation in each instance, no need to animate anything.</p>
  <p>I have tried with GLTF1.0 and GLTF2.0 and the issue is the same.
  When I load the GLTF model, I get a scene. From this scene I am trying to obtain the buffergeometry from children array. However when I try to créate an instance, it is not working. My objects are static (no animations at all).</p>
  <p><strong>Is there any way to create an instance of an Object3D or from its buffergeometry?</strong></p>
  <p>In BABYLONJS it is very simple to create instances from a loaded GLTF file. I really need to use instances to save RAM and use GPU instead CPU resources. My scene needs to load many copies of the same objects to compound the scene.</p>
  <p>Some problems I see using GLFT loader:</p>
  <ul>
  <li>
  <ol>
  <li>You have to identify all object3Ds which contain the valid geometry. In this example is on line 335:</li>
  </ol>
  <p><code>var geo = data.scene.children[0].children[0].children[0].children[0].geometry</code></p>
  </li>
  <li>
  <ol start="2">
  <li>The merge example is not working. it doesn't work either in the original example.</li>
  </ol>
  </li>
  <li>
  <ol start="3">
  <li>IT seems that instancing do not improve performance at all:</li>
  </ol>
  </li>
  <li><p>10000 objects, multimaterial --&gt; 4FPS</p>
  </li>
  <li><p>10000 objects, singlematerial--&gt; 4FPS</p>
  </li>
  <li><p>10000 objects, instanced --&gt; 4FPS</p>
  </li>
  <li><p>10000 objects, merged --&gt; Not working</p>
  </li>
  <li>
  <ol start="4">
  <li>When instanced is selected the geometries are not properly rendered.</li>
  </ol>
  </li>
  </ul>
  <p>Here you have my code using Duck GLTF example:</p>
  <pre class="lang-html prettyprint-override"><code>&lt;!DOCTYPE html&gt;
  &lt;html lang=&quot;en&quot;&gt;
    &lt;head&gt;
      &lt;title&gt;three.js webgl - interactive instances (gpu)&lt;/title&gt;
      &lt;meta charset=&quot;utf-8&quot; /&gt;
      &lt;meta
        name=&quot;viewport&quot;
        content=&quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&quot;
      /&gt;
      &lt;style&gt;
        body {
          font-family: Monospace;
          background-color: #f0f0f0;
          margin: 0px;
          overflow: hidden;
        }
        .info {
          position: absolute;
          background-color: black;
          opacity: 0.8;
          color: white;
          text-align: center;
          top: 0px;
          width: 100%;
        }
        .info a {
          color: #00ffff;
        }
        #notSupported {
          width: 50%;
          margin: auto;
          border: 2px red solid;
          margin-top: 20px;
          padding: 10px;
        }
      &lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;div class=&quot;info&quot;&gt;
        &lt;a href=&quot;http://threejs.org&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;three.js&lt;/a&gt;
        webgl - gpu picking of geometry instances
        &lt;div id=&quot;notSupported&quot; style=&quot;display: none&quot;&gt;
          Sorry your graphics card + browser does not support hardware instancing
        &lt;/div&gt;
        &lt;br /&gt;&lt;br /&gt;
        &lt;div&gt;
          This demo compares different methods of constructing and rendering many
          instances of a single geometry.
        &lt;/div&gt;
        &lt;br /&gt;
        &lt;div&gt;
          &lt;div style=&quot;display: inline-block&quot;&gt;
            &lt;span&gt;number of&lt;br /&gt;geometry instances&lt;/span&gt;
            &lt;br /&gt;
            &lt;select id=&quot;instanceCount&quot;&gt;
              &lt;option&gt;100&lt;/option&gt;
              &lt;option&gt;500&lt;/option&gt;
              &lt;option selected&gt;1000&lt;/option&gt;
              &lt;option&gt;2000&lt;/option&gt;
              &lt;option&gt;3000&lt;/option&gt;
              &lt;option&gt;5000&lt;/option&gt;
              &lt;option&gt;10000&lt;/option&gt;
              &lt;option&gt;20000&lt;/option&gt;
              &lt;option&gt;30000&lt;/option&gt;
              &lt;option&gt;50000&lt;/option&gt;
              &lt;option&gt;100000&lt;/option&gt;
            &lt;/select&gt;
          &lt;/div&gt;
          &amp;nbsp;&amp;nbsp;&amp;nbsp;
          &lt;div style=&quot;display: inline-block&quot;&gt;
            &lt;span&gt;method of&lt;br /&gt;construction/rendering&lt;/span&gt;
            &lt;br /&gt;
            &lt;select id=&quot;method&quot;&gt;
              &lt;option&gt;instanced&lt;/option&gt;
              &lt;option&gt;merged&lt;/option&gt;
              &lt;option selected&gt;singleMaterial&lt;/option&gt;
              &lt;option&gt;multiMaterial&lt;/option&gt;
            &lt;/select&gt;
          &lt;/div&gt;
          &amp;nbsp;&amp;nbsp;&amp;nbsp;
          &lt;div style=&quot;display: inline-block&quot;&gt;
            &lt;span&gt;render continuously&lt;br /&gt;(to get fps reading)&lt;/span&gt;
            &lt;br /&gt;
            &lt;input id=&quot;animate&quot; type=&quot;checkbox&quot; /&gt;
          &lt;/div&gt;
          &amp;nbsp;&amp;nbsp;&amp;nbsp;
          &lt;div style=&quot;display: inline-block&quot;&gt;
            &lt;span
              &gt;use override material&lt;br /&gt;(only effects singleMaterial
              method)&lt;/span
            &gt;
            &lt;br /&gt;
            &lt;input id=&quot;override&quot; type=&quot;checkbox&quot; checked /&gt;
          &lt;/div&gt;
          &amp;nbsp;&amp;nbsp;&amp;nbsp;
          &lt;div style=&quot;display: inline-block&quot;&gt;
            &lt;span&gt;construct anew&lt;br /&gt;(to get additional timings)&lt;/span&gt;
            &lt;br /&gt;
            &lt;button id=&quot;construct&quot; type=&quot;button&quot;&gt;do it&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;br /&gt;
        &lt;div&gt;
          &lt;span&gt;Materials: #&lt;span id=&quot;materialCount&quot;&gt;&lt;/span&gt;&lt;/span&gt;
          &amp;nbsp;&amp;nbsp;&amp;nbsp;
          &lt;span&gt;Objects: #&lt;span id=&quot;objectCount&quot;&gt;&lt;/span&gt;&lt;/span&gt;
          &amp;nbsp;&amp;nbsp;&amp;nbsp;
          &lt;span&gt;Drawcalls: #&lt;span id=&quot;drawcalls&quot;&gt;&lt;/span&gt;&lt;/span&gt;
          &amp;nbsp;&amp;nbsp;&amp;nbsp;
          &lt;span&gt;Construction time: &lt;span id=&quot;initTime&quot;&gt;&lt;/span&gt;&amp;nbsp;ms&lt;/span&gt;
          &amp;nbsp;&amp;nbsp;&amp;nbsp;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div id=&quot;container&quot;&gt;&lt;/div&gt;
      &lt;script src=&quot;../build/three.js&quot;&gt;&lt;/script&gt;
      &lt;script src=&quot;js/controls/TrackballControls.js&quot;&gt;&lt;/script&gt;
      &lt;script src=&quot;js/libs/stats.min.js&quot;&gt;&lt;/script&gt;
      &lt;script src=&quot;js/loaders/GLTF2Loader.js&quot;&gt;&lt;/script&gt;
      &lt;script id=&quot;vertMerged&quot; type=&quot;x-shader/x-vertex&quot;&gt;
        #define SHADER_NAME vertMerged
        precision highp float;
        uniform mat4 modelViewMatrix;
        uniform mat4 projectionMatrix;
        attribute vec3 position;
        #ifdef PICKING
        attribute vec3 pickingColor;
        #else
        attribute vec3 color;
        varying vec3 vPosition;
        #endif
        varying vec3 vColor;
        void main()   {
        vec3 positionEye = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
        #ifdef PICKING
        vColor = pickingColor;
        #else
        vColor = color;
        vPosition = positionEye;
        #endif
        gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
        }
      &lt;/script&gt;
      &lt;script id=&quot;fragMerged&quot; type=&quot;x-shader/x-fragment&quot;&gt;
        #define SHADER_NAME fragMerged
        #extension GL_OES_standard_derivatives : enable
        precision highp float;
        varying vec3 vColor;
        #ifndef PICKING
        varying vec3 vPosition;
        #endif
        void main()   {
        #ifdef PICKING
        gl_FragColor = vec4( vColor, 1.0 );
        #else
        vec3 fdx = dFdx( vPosition );
        vec3 fdy = dFdy( vPosition );
        vec3 normal = normalize( cross( fdx, fdy ) );
        float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
        gl_FragColor = vec4( diffuse * vColor, 1.0 );
        #endif
        }
      &lt;/script&gt;
      &lt;script id=&quot;vertInstanced&quot; type=&quot;x-shader/x-vertex&quot;&gt;
        #define SHADER_NAME vertInstanced
        precision highp float;
        uniform mat4 modelViewMatrix;
        uniform mat4 projectionMatrix;
        attribute vec3 position;
        attribute vec3 mcol0;
        attribute vec3 mcol1;
        attribute vec3 mcol2;
        attribute vec3 mcol3;
        #ifdef PICKING
        attribute vec3 pickingColor;
        #else
        attribute vec3 color;
        varying vec3 vPosition;
        #endif
        varying vec3 vColor;
        void main()   {
        mat4 matrix = mat4(
        vec4( mcol0, 0 ),
        vec4( mcol1, 0 ),
        vec4( mcol2, 0 ),
        vec4( mcol3, 1 )
        );
        vec3 positionEye = ( modelViewMatrix * matrix * vec4( position, 1.0 ) ).xyz;
        #ifdef PICKING
        vColor = pickingColor;
        #else
        vColor = color;
        vPosition = positionEye;
        #endif
        gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
        }
      &lt;/script&gt;
      &lt;script id=&quot;fragInstanced&quot; type=&quot;x-shader/x-fragment&quot;&gt;
        #define SHADER_NAME fragInstanced
        #extension GL_OES_standard_derivatives : enable
        precision highp float;
        varying vec3 vColor;
        #ifndef PICKING
        varying vec3 vPosition;
        #endif
        void main()   {
        #ifdef PICKING
        gl_FragColor = vec4( vColor, 1.0 );
        #else
        vec3 fdx = dFdx( vPosition );
        vec3 fdy = dFdy( vPosition );
        vec3 normal = normalize( cross( fdx, fdy ) );
        float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
        gl_FragColor = vec4( diffuse * vColor, 1.0 );
        #endif
        }
      &lt;/script&gt;
      &lt;script id=&quot;vertMaterial&quot; type=&quot;x-shader/x-vertex&quot;&gt;
        #define SHADER_NAME vertMaterial
        precision highp float;
        uniform mat4 modelViewMatrix;
        uniform mat4 projectionMatrix;
        attribute vec3 position;
        #ifndef PICKING
        varying vec3 vPosition;
        #endif
        void main()   {
        vec3 positionEye = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
        #ifndef PICKING
        vPosition = positionEye;
        #endif
        gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
        }
      &lt;/script&gt;
      &lt;script id=&quot;fragMaterial&quot; type=&quot;x-shader/x-fragment&quot;&gt;
        #define SHADER_NAME fragMaterial
        #extension GL_OES_standard_derivatives : enable
        precision highp float;
        #ifdef PICKING
        uniform vec3 pickingColor;
        #else
        uniform vec3 color;
        varying vec3 vPosition;
        #endif
        void main()   {
        #ifdef PICKING
        gl_FragColor = vec4( pickingColor, 1.0 );
        #else
        vec3 fdx = dFdx( vPosition );
        vec3 fdy = dFdy( vPosition );
        vec3 normal = normalize( cross( fdx, fdy ) );
        float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
        gl_FragColor = vec4( diffuse * color, 1.0 );
        #endif
        }
      &lt;/script&gt;
      &lt;script&gt;
        var container, stats;
        var camera, controls, scene, renderer;
        var pickingData, pickingRenderTarget, pickingScene;
        var useOverrideMaterial = true;
        var singleMaterial, singlePickingMaterial;
        var highlightBox;
        var materialList = [];
        var geometryList = [];
        var objectCount = 0;
        var geometrySize;
        var mouse = new THREE.Vector2();
        var scale = 1.03;
        var loader = new THREE.GLTF2Loader();
        var pixelBuffer = new Uint8Array(4);
        var instanceCount, method, doAnimate;
        gui();
        init();
        initMesh();
        if (doAnimate) animate();
        function gui() {
          var instanceCountElm = document.getElementById(&quot;instanceCount&quot;);
          instanceCount = parseInt(instanceCountElm.value);
          instanceCountElm.addEventListener(&quot;change&quot;, function () {
            instanceCount = parseInt(instanceCountElm.value);
            initMesh();
          });
          var methodElm = document.getElementById(&quot;method&quot;);
          method = methodElm.value;
          methodElm.addEventListener(&quot;change&quot;, function () {
            method = methodElm.value;
            initMesh();
          });
          var animateElm = document.getElementById(&quot;animate&quot;);
          doAnimate = animateElm.checked;
          animateElm.addEventListener(&quot;click&quot;, function () {
            doAnimate = animateElm.checked;
            animate();
          });
          var overrideElm = document.getElementById(&quot;override&quot;);
          useOverrideMaterial = overrideElm.checked;
          overrideElm.addEventListener(&quot;click&quot;, function () {
            useOverrideMaterial = overrideElm.checked;
            initMesh();
          });
          var constructElm = document.getElementById(&quot;construct&quot;);
          constructElm.addEventListener(&quot;click&quot;, function () {
            initMesh();
          });
        }
        function clean() {
          THREE.Cache.clear();
          materialList.forEach(function (m) {
            m.dispose();
          });
          geometryList.forEach(function (g) {
            g.dispose();
          });
          scene = new THREE.Scene();
          scene.background = new THREE.Color(0xffffff);
          scene.add(camera);
          scene.add(highlightBox);
          pickingScene = new THREE.Scene();
          pickingData = {};
          materialList = [];
          geometryList = [];
          objectCount = 0;
          singleMaterial = undefined;
          singlePickingMaterial = undefined;
        }
        var randomizeMatrix = (function () {
          var position = new THREE.Vector3();
          var rotation = new THREE.Euler();
          var quaternion = new THREE.Quaternion();
          var 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, false);
            scale.x = scale.y = scale.z = 0.001;
            matrix.compose(position, quaternion, scale);
          };
        })();
        function initMesh() {
          clean();
          loader.load(&quot;models/gltf/Duck/glTF-Binary/Duck.glb&quot;, function (data) {
            console.log(data);
            var geo =
              data.scene.children[0].children[0].children[0].children[0].geometry;
            console.log(&quot;geo:&quot;);
            console.log(geo);
            geo.computeBoundingBox();
            geometrySize = geo.boundingBox.getSize();
            geometryList.push(geo);
            var start = window.performance.now();
            switch (method) {
              case &quot;merged&quot;:
                makeMerged(geo);
                break;
              case &quot;instanced&quot;:
                makeInstanced(geo);
                break;
              case &quot;singleMaterial&quot;:
                makeSingleMaterial(geo);
                break;
              case &quot;multiMaterial&quot;:
                makeMultiMaterial(geo);
                break;
            }
            render();
            var end = window.performance.now();
            document.getElementById(&quot;materialCount&quot;).innerText =
              materialList.length;
            document.getElementById(&quot;objectCount&quot;).innerText = objectCount;
            document.getElementById(&quot;drawcalls&quot;).innerText =
              renderer.info.render.calls;
            document.getElementById(&quot;initTime&quot;).innerText = (end - start).toFixed(
              2
            );
          });
        }
        function makeMultiMaterial(geo) {
          var vert = document.getElementById(&quot;vertMaterial&quot;).textContent;
          var frag = document.getElementById(&quot;fragMaterial&quot;).textContent;
          var material = new THREE.RawShaderMaterial({
            vertexShader: vert,
            fragmentShader: frag,
            uniforms: {
              color: {
                value: new THREE.Color(),
              },
            },
          });
          var pickingMaterial = new THREE.RawShaderMaterial({
            vertexShader: &quot;#define PICKING\n&quot; + vert,
            fragmentShader: &quot;#define PICKING\n&quot; + frag,
            uniforms: {
              pickingColor: {
                value: new THREE.Color(),
              },
            },
          });
          var matrix = new THREE.Matrix4();
          for (var i = 0; i &lt; instanceCount; i++) {
            var object = new THREE.Mesh(geo, material);
            objectCount++;
            randomizeMatrix(matrix);
            object.applyMatrix(matrix);
            var pickingObject = object.clone();
            objectCount++;
            object.material = material.clone();
            object.material.uniforms.color.value.setHex(Math.random() * 0xffffff);
            materialList.push(object.material);
            pickingObject.material = pickingMaterial.clone();
            pickingObject.material.uniforms.pickingColor.value.setHex(i + 1);
            materialList.push(pickingObject.material);
            pickingData[i + 1] = object;
            scene.add(object);
            pickingScene.add(pickingObject);
          }
          material.dispose();
          pickingMaterial.dispose();
        }
        function makeSingleMaterial(geo) {
          var vert = document.getElementById(&quot;vertMaterial&quot;).textContent;
          var frag = document.getElementById(&quot;fragMaterial&quot;).textContent;
          var material = new THREE.RawShaderMaterial({
            vertexShader: vert,
            fragmentShader: frag,
            uniforms: {
              color: {
                value: new THREE.Color(),
              },
            },
          });
          materialList.push(material);
          var pickingMaterial = new THREE.RawShaderMaterial({
            vertexShader: &quot;#define PICKING\n&quot; + vert,
            fragmentShader: &quot;#define PICKING\n&quot; + frag,
            uniforms: {
              pickingColor: {
                value: new THREE.Color(),
              },
            },
          });
          materialList.push(pickingMaterial);
          if (useOverrideMaterial) {
            singleMaterial = material;
            singlePickingMaterial = pickingMaterial;
          }
          var matrix = new THREE.Matrix4();
          function onBeforeRender(
            renderer,
            scene,
            camera,
            geometry,
            material,
            group
          ) {
            var updateList = [];
            var u = material.uniforms;
            var d = this.userData;
            if (u.pickingColor) {
              u.pickingColor.value.setHex(d.pickingColor);
              updateList.push(&quot;pickingColor&quot;);
            }
            if (u.color) {
              u.color.value.setHex(d.color);
              updateList.push(&quot;color&quot;);
            }
            if (updateList.length) {
              var materialProperties = renderer.properties.get(material);
              if (materialProperties.program) {
                var gl = renderer.getContext();
                var p = materialProperties.program;
                gl.useProgram(p.program);
                var pu = p.getUniforms();
                updateList.forEach(function (name) {
                  pu.setValue(gl, name, u[name].value);
                });
              }
            }
          }
          for (var i = 0; i &lt; instanceCount; i++) {
            var object = new THREE.Mesh(geo, material);
            objectCount++;
            randomizeMatrix(matrix);
            object.applyMatrix(matrix);
            var pickingObject;
            if (!useOverrideMaterial) {
              pickingObject = object.clone();
              objectCount++;
            }
            object.material = material;
            object.userData[&quot;color&quot;] = Math.random() * 0xffffff;
            if (useOverrideMaterial) {
              object.userData[&quot;pickingColor&quot;] = i + 1;
              object.onBeforeRender = onBeforeRender;
            } else {
              pickingObject.material = pickingMaterial;
              pickingObject.userData[&quot;pickingColor&quot;] = i + 1;
              pickingObject.onBeforeRender = onBeforeRender;
            }
            pickingData[i + 1] = object;
            scene.add(object);
            if (!useOverrideMaterial) pickingScene.add(pickingObject);
          }
        }
        function makeMerged(geo) {
          var vert = document.getElementById(&quot;vertMerged&quot;).textContent;
          var frag = document.getElementById(&quot;fragMerged&quot;).textContent;
          var material = new THREE.RawShaderMaterial({
            vertexShader: vert,
            fragmentShader: frag,
          });
          materialList.push(material);
          var pickingMaterial = new THREE.RawShaderMaterial({
            vertexShader: &quot;#define PICKING\n&quot; + vert,
            fragmentShader: &quot;#define PICKING\n&quot; + frag,
          });
          materialList.push(pickingMaterial);
          var bgeo = geo.clone();
          geometryList.push(bgeo);
          var mgeo = new THREE.BufferGeometry();
          geometryList.push(mgeo);
          var pos = bgeo.attributes.position;
          var posLen = bgeo.attributes.position.count * 3;
          var vertices = new THREE.BufferAttribute(
            new Float32Array(instanceCount * posLen),
            3
          );
  
          var matrix = new THREE.Matrix4();
          for (var i = 0, ul = instanceCount; i &lt; ul; i++) {
            randomizeMatrix(matrix);
            var object = new THREE.Object3D();
            objectCount++;
            object.applyMatrix(matrix);
            pickingData[i + 1] = object;
            vertices.set(pos.array, i * posLen);
            //matrix.applyToVector3Array( vertices.array, i * posLen, posLen )
          }
          mgeo.addAttribute(&quot;position&quot;, vertices);
          var colCount = posLen / 3;
          var colors = new THREE.BufferAttribute(
            new Float32Array(instanceCount * colCount * 3),
            3
          );
  
          var randCol = function () {
            return Math.random();
          };
          for (var i = 0, ul = instanceCount; i &lt; ul; i++) {
            var r = randCol(),
              g = randCol(),
              b = randCol();
            for (var j = i * colCount, jl = (i + 1) * colCount; j &lt; jl; j++) {
              colors.setXYZ(j, r, g, b);
            }
          }
          mgeo.addAttribute(&quot;color&quot;, colors);
          var col = new THREE.Color();
          var pickingColors = new THREE.BufferAttribute(
            new Float32Array(instanceCount * colCount * 3),
            3
          );
          for (var i = 0, ul = instanceCount; i &lt; ul; i++) {
            col.setHex(i + 1);
            for (var j = i * colCount, jl = (i + 1) * colCount; j &lt; jl; j++) {
              pickingColors.setXYZ(j, col.r, col.g, col.b);
            }
          }
          mgeo.addAttribute(&quot;pickingColor&quot;, pickingColors);
          var mesh = new THREE.Mesh(mgeo, material);
          scene.add(mesh);
          var pickingMesh = new THREE.Mesh(mgeo, pickingMaterial);
          pickingScene.add(pickingMesh);
        }
        function makeInstanced(geo) {
          var vert = document.getElementById(&quot;vertInstanced&quot;).textContent;
          var frag = document.getElementById(&quot;fragInstanced&quot;).textContent;
          var material = new THREE.RawShaderMaterial({
            vertexShader: vert,
            fragmentShader: frag,
          });
          materialList.push(material);
          var pickingMaterial = new THREE.RawShaderMaterial({
            vertexShader: &quot;#define PICKING\n&quot; + vert,
            fragmentShader: &quot;#define PICKING\n&quot; + frag,
          });
          materialList.push(pickingMaterial);
          var bgeo = geo.clone();
          geometryList.push(bgeo);
          var igeo = new THREE.InstancedBufferGeometry();
          geometryList.push(igeo);
          var vertices = bgeo.attributes.position.clone();
          igeo.addAttribute(&quot;position&quot;, vertices);
          var mcol0 = new THREE.InstancedBufferAttribute(
            new Float32Array(instanceCount * 3),
            3,
            1
          );
          var mcol1 = new THREE.InstancedBufferAttribute(
            new Float32Array(instanceCount * 3),
            3,
            1
          );
          var mcol2 = new THREE.InstancedBufferAttribute(
            new Float32Array(instanceCount * 3),
            3,
            1
          );
          var mcol3 = new THREE.InstancedBufferAttribute(
            new Float32Array(instanceCount * 3),
            3,
            1
          );
          var matrix = new THREE.Matrix4();
          var me = matrix.elements;
          for (var i = 0, ul = mcol0.count; i &lt; ul; i++) {
            randomizeMatrix(matrix);
            var object = new THREE.Object3D();
            objectCount++;
            object.applyMatrix(matrix);
            pickingData[i + 1] = object;
            mcol0.setXYZ(i, me[0], me[1], me[2]);
            mcol1.setXYZ(i, me[4], me[5], me[6]);
            mcol2.setXYZ(i, me[8], me[9], me[10]);
            mcol3.setXYZ(i, me[12], me[13], me[14]);
          }
          igeo.addAttribute(&quot;mcol0&quot;, mcol0);
          igeo.addAttribute(&quot;mcol1&quot;, mcol1);
          igeo.addAttribute(&quot;mcol2&quot;, mcol2);
          igeo.addAttribute(&quot;mcol3&quot;, mcol3);
          var randCol = function () {
            return Math.random();
          };
          var colors = new THREE.InstancedBufferAttribute(
            new Float32Array(instanceCount * 3),
            3,
            1
          );
          for (var i = 0, ul = colors.count; i &lt; ul; i++) {
            colors.setXYZ(i, randCol(), randCol(), randCol());
          }
          igeo.addAttribute(&quot;color&quot;, colors);
          var col = new THREE.Color();
          var pickingColors = new THREE.InstancedBufferAttribute(
            new Float32Array(instanceCount * 3),
            3,
            1
          );
          for (var i = 0, ul = pickingColors.count; i &lt; ul; i++) {
            col.setHex(i + 1);
            pickingColors.setXYZ(i, col.r, col.g, col.b);
          }
          igeo.addAttribute(&quot;pickingColor&quot;, pickingColors);
          var mesh = new THREE.Mesh(igeo, material);
          scene.add(mesh);
          var pickingMesh = new THREE.Mesh(igeo, pickingMaterial);
          pickingScene.add(pickingMesh);
        }
        function init() {
          camera = new THREE.PerspectiveCamera(
            70,
            window.innerWidth / window.innerHeight,
            1,
            100
          );
          camera.position.z = 40;
          pickingRenderTarget = new THREE.WebGLRenderTarget(
            window.innerWidth,
            window.innerHeight
          );
          pickingRenderTarget.texture.generateMipmaps = false;
          pickingRenderTarget.texture.minFilter = THREE.NearestFilter;
          highlightBox = new THREE.Mesh(
            new THREE.BoxGeometry(1, 1, 1),
            new THREE.MeshLambertMaterial({
              emissive: 0xffff00,
              transparent: true,
              opacity: 0.5,
              side: THREE.FrontSide,
            })
          );
          container = document.getElementById(&quot;container&quot;);
          renderer = new THREE.WebGLRenderer({
            antialias: true,
            alpha: true,
          });
          if (renderer.extensions.get(&quot;ANGLE_instanced_arrays&quot;) === false) {
            document.getElementById(&quot;notSupported&quot;).style.display = &quot;&quot;;
            return;
          }
          renderer.setPixelRatio(window.devicePixelRatio);
          renderer.setSize(window.innerWidth, window.innerHeight);
          container.appendChild(renderer.domElement);
          if (renderer.extensions.get(&quot;ANGLE_instanced_arrays&quot;) === false) {
            throw &quot;ANGLE_instanced_arrays not supported&quot;;
          }
          controls = new THREE.TrackballControls(camera, renderer.domElement);
          controls.staticMoving = true;
          stats = new Stats();
          container.appendChild(stats.dom);
          renderer.domElement.addEventListener(&quot;mousemove&quot;, onMouseMove);
          window.addEventListener(&quot;resize&quot;, onWindowResize, false);
        }
        //
        function onMouseMove(e) {
          mouse.x = e.clientX;
          mouse.y = e.clientY;
          controls.update();
          requestAnimationFrame(render);
        }
        function onWindowResize(event) {
          camera.aspect = window.innerWidth / window.innerHeight;
          camera.updateProjectionMatrix();
          renderer.setSize(window.innerWidth, window.innerHeight);
          pickingRenderTarget.setSize(window.innerWidth, window.innerHeight);
        }
        function animate() {
          if (doAnimate) {
            requestAnimationFrame(animate);
          }
          controls.update();
          stats.update();
          document.getElementById(&quot;materialCount&quot;).innerText =
            materialList.length;
          document.getElementById(&quot;objectCount&quot;).innerText = objectCount;
          document.getElementById(&quot;drawcalls&quot;).innerText =
            renderer.info.render.calls;
          render();
        }
        function pick() {
          highlightBox.visible = false;
          if (singlePickingMaterial) {
            scene.overrideMaterial = singlePickingMaterial;
            renderer.render(scene, camera, pickingRenderTarget);
            scene.overrideMaterial = null;
          } else {
            renderer.render(pickingScene, camera, pickingRenderTarget);
          }
          renderer.readRenderTargetPixels(
            pickingRenderTarget,
            mouse.x,
            pickingRenderTarget.height - mouse.y,
            1,
            1,
            pixelBuffer
          );
          var id =
            (pixelBuffer[0] &lt;&lt; 16) | (pixelBuffer[1] &lt;&lt; 8) | pixelBuffer[2];
          var object = pickingData[id];
          if (object) {
            if (object.position &amp;&amp; object.rotation &amp;&amp; object.scale) {
              highlightBox.position.copy(object.position);
              highlightBox.rotation.copy(object.rotation);
              highlightBox.scale
                .copy(object.scale)
                .multiply(geometrySize)
                .multiplyScalar(scale);
              highlightBox.visible = true;
            }
          } else {
            highlightBox.visible = false;
          }
        }
        function render() {
          pick();
          renderer.render(scene, camera);
        }
      &lt;/script&gt;
    &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>