title: Three js PERFORMANCE how to make using image textures faster
body: <p>I have code. Sorry I don't have the images to upload. 
  In the code I have two functions.<br>
  <code>UseMeshNormalMaterial()</code> and <code>UsePngMaterial()</code> 
  This is so you can easily test the code if you have some images laying around. 
  (uncomment one or the other and load the page)
  The difference between the two calls is <code>UseMeshNormalMaterial</code> uses a <code>MeshNormalMaterial</code> and <code>UsePngMaterial</code> uses an indexed array of <code>MeshBasicMaterial</code>'s. The difference is startling. <code>UseMeshNormalMaterial</code> runs free at 60fp while <code>UsePngMaterial</code> runs at 0 to 2 fps. </p>
  
  <p>So I need help or direction. I will take any ideas at this point. </p>
  
  <p>Here is the code. </p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
   &lt;meta charset=utf-8&gt;
   &lt;meta name="viewport" content="width=device-width, minimum-scale=1.0"&gt;
   &lt;title&gt;TestHTML&lt;/title&gt;
   &lt;style&gt;
    body {
     background: #fff;
     padding: 0;
     margin: 0;
     font-weight: bold;
     overflow: hidden;
    }
   &lt;/style&gt;
  
  
  &lt;/head&gt;
  
  &lt;body style="margin: 0;"&gt;
  
  
  
   &lt;script src="js/three.min.js"&gt;&lt;/script&gt;
   &lt;script src="js/stats.min.js"&gt;&lt;/script&gt;
  
  
  
   &lt;script&gt;
  
          var camera = new THREE.PerspectiveCamera( 30, window.innerWidth/window.innerHeight, 0.1, 5000.0);
          var mouseX = 0, mouseY = 0;
  
          var aspectratio = window.innerWidth/window.innerHeight;
          var renderer = new THREE.WebGLRenderer();
  
          renderer.setSize(window.innerWidth, window.innerHeight);
                   renderer.shadowMap.cullFace = THREE.CullFaceFrontBack;
          renderer.gammaInput = true;
          renderer.gammaOutput = true;
  
          renderer.shadowMap.enabled = false;
          renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  
          document.body.appendChild( renderer.domElement );
  
          var scene = new THREE.Scene();
          scene.add(camera);
  
          document.addEventListener( 'mousemove', onDocumentMouseMove, false );
  
          window.addEventListener('resize', resize, false);
  
          var windowHalfX = window.innerWidth / 2;
          var windowHalfY = window.innerHeight / 2;
  
  
          // Our Javascript will go here.
          stats = new Stats();
          stats.domElement.style.position = 'absolute';
          stats.domElement.style.top = '0px';
          stats.domElement.style.zIndex = 100;
          document.body.appendChild( stats.domElement );
  
  
          // this  must be defined before MJMotion.js
          // we use it in there.
          var scenesizereduction = 100.0;
  
          var directionalLight = new THREE.DirectionalLight(0xffffff, 0.15);
  
          directionalLight.position.set(-100, 1000,2000);
          scene.add(directionalLight);
  
  
  
           var hemiLight = new THREE.HemisphereLight(0xAAAAAA, 0x080808, 0.25);
           hemiLight.position.set(0, 500, 0);
           scene.add(hemiLight);
  
  
           var  dirLight = new THREE.DirectionalLight( 0xffffff, 0 );
                       dirLight.color.setHSL( 0.1, 1, 0.95 );
                       dirLight.position.set( -1, 1.75, 1 );
                       dirLight.position.multiplyScalar( 50 );
                       scene.add( dirLight );
  
                       dirLight.castShadow = false;
  
                       dirLight.shadowMapWidth = 2048;
                       dirLight.shadowMapHeight = 2048;
  
                       var d = 150;
  
                       dirLight.shadowCameraLeft = -d;
                       dirLight.shadowCameraRight = d;
                       dirLight.shadowCameraTop = d;
                       dirLight.shadowCameraBottom = -d;
  
                       dirLight.shadowCameraFar = 3500;
                       dirLight.shadowBias = -0.00005;
  
  
  
  
  
      var textures20Geometry = new THREE.BoxGeometry(2.0,0.95 , .80 );
      var textures40Geometry = new THREE.BoxGeometry(4.0 , 0.95, .80 );
      var Cube20Mesh= new THREE.Mesh( textures20Geometry);
      var Cube40Mesh= new THREE.Mesh(textures40Geometry);
      var CubeGeometry = new THREE.Geometry();
  
      //Add grid
      var gridXZ = new THREE.GridHelper(1000, 100);
      gridXZ.setColors( new THREE.Color(0x8f8f8f), new THREE.Color(0x8f8f8f) );
      gridXZ.position.set(0,0,0 );
      scene.add(gridXZ);
  
  
  
      var CubeMaterials = [
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube01.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube02.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube03.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube04.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube05.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube06.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube07.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube08.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube09.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube10.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube11.png')}),
  
        new THREE.MeshBasicMaterial({
          map: THREE.ImageUtils.loadTexture('textures/cube12.png')})
      ];
  
  
  
   var objects = [];
   var material = new THREE.MeshNormalMaterial();
  
   // here are the two lines of code that make all the difference.
   //use one of the other.
   // VERY fast using NO image textures.
   UseMeshNormalMaterial();
  
   // VERY slow using image textures.
  // UsePngMaterial();
  
   animate();
  
  
  
  function UseMeshNormalMaterial()
  {
  
   for(var i = 0; i &lt; 25000; i++)
    {
     addCube20("cube" + i, (Math.random() * 500) - 50, (Math.random() * 500) - 50, Math.random() * 2 * Math.PI,1);
  
     addCube40("cube" + i, (Math.random() * 500) - 50, (Math.random() * 500) - 50, Math.random() * 2 * Math.PI,6);
    }
  
   DisplayCubes();
  }
  
  function UsePngMaterial()
  {
  
   for(var i = 0; i &lt; 25000; i++)
    {
     addCube201("cube" + i, (Math.random() * 500) - 50, (Math.random() * 500) - 50, Math.random() * 2 * Math.PI,1);
  
     addCube401("cube" + i, (Math.random() * 500) - 50, (Math.random() * 500) - 50, Math.random() * 2 * Math.PI,6);
    }
  
   DisplayCubes1();
  
  }
  
  
  function addCube20(name, x1,z1,azimuth,MaterialIndex)
   {
    Cube20Mesh.position.set(x1, (Math.random() * 100) - 100, z1);
    Cube20Mesh.rotation.x =  azimuth;
    Cube20Mesh.rotation.y =  Math.random() * 2 * Math.PI;
    Cube20Mesh.name = name;
    Cube20Mesh.updateMatrix();
    CubeGeometry.merge(Cube20Mesh.geometry, Cube20Mesh.matrix);
   };
  
  
  function addCube40(name, x1,z1,azimuth,MaterialIndex)
  {
   Cube40Mesh.position.set(x1, (Math.random() * 100) - 100, z1);
   Cube40Mesh.rotation.x = azimuth;
   Cube40Mesh.rotation.y = Math.random() * 2 * Math.PI;
   Cube40Mesh.name = name;
   Cube40Mesh.updateMatrix();
   CubeGeometry.merge(Cube40Mesh.geometry, Cube40Mesh.matrix);
   };
  
  
   function addCube201(name, x1,z1,azimuth,MaterialIndex)
    {
     Cube20Mesh.position.set(x1, (Math.random() * 100) - 100, z1);
     Cube20Mesh.rotation.x =  azimuth;
     Cube20Mesh.rotation.y =  Math.random() * 2 * Math.PI;
     Cube20Mesh.name = name;
     Cube20Mesh.updateMatrix();
     CubeGeometry.merge(Cube20Mesh.geometry, Cube20Mesh.matrix,MaterialIndex);
    };
  
  
   function addCube401(name, x1,z1,azimuth,MaterialIndex)
    {
     Cube40Mesh.position.set(x1, (Math.random() * 100) - 100, z1);
     Cube40Mesh.rotation.x = azimuth;
     Cube40Mesh.rotation.y = Math.random() * 2 * Math.PI;
     Cube40Mesh.name = name;
     Cube40Mesh.updateMatrix();
     CubeGeometry.merge(Cube40Mesh.geometry, Cube40Mesh.matrix,MaterialIndex);
    };
  
  
  
  function DisplayCubes()
   {
     var CubeGroup = new THREE.Mesh(CubeGeometry,  material);
     CubeGroup.matrixAutoUpdate = false;
     CubeGroup.updateMatrix();
     scene.add(CubeGroup);
   };
  
  function DisplayCubes1()
   {
    var CubeGroup = new THREE.Mesh(CubeGeometry, new THREE.MeshFaceMaterial(CubeMaterials));
    CubeGroup.matrixAutoUpdate = false;
    CubeGroup.updateMatrix();
    scene.add(CubeGroup);
   };
  
  
   function onDocumentMouseMove(event)
    {
     mouseX = ( event.clientX - windowHalfX ) * 10;
     mouseY = ( event.clientY - windowHalfY ) * 10;
    };
  
  
   function resize()
    {
     windowHalfX = window.innerWidth / 2;
     windowHalfY = window.innerHeight / 2;
     renderer.setSize(window.innerWidth, window.innerHeight);
     camera.aspect = window.innerWidth / window.innerHeight;
     camera.updateProjectionMatrix();
    };
  
  
    function animate()
     {
      camera.position.x += ( mouseX - camera.position.x ) * .005;
      camera.position.y += ( - mouseY - camera.position.y ) * .005;
      camera.lookAt( scene.position );
      for ( var i = 0, il = objects.length; i &lt; il; i ++ )
       {
        objects[ i ].rotation.x += 0.01;
        objects[ i ].rotation.y += 0.02;
       }
  
      requestAnimationFrame( animate );
      renderer.render(scene, camera);
      stats.update();
     };
  
  
  
  
   &lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>