0
votes

This follows onto this question I asked a few days ago which turned out like the following:

(function onLoad() {
  var canvasElement;
  var width, height;
  var scene, camera;
  var renderer;
  var controls;

  var pivot;
  var bagMesh;
  var planeMesh;

  const objLoader = new THREE.OBJLoader2();
  const fileLoader = new THREE.FileLoader();
  const textureLoader = new THREE.TextureLoader();

  init();

  function init() {
    container = document.getElementById('container');
    initScene();
    addGridHelper();
    addCamera();
    addLighting();
    addRenderer();
    addOrbitControls();

    loadCubeObj();

    // Logic
    var update = function() {};

    // Draw scene
    var render = function() {
      renderer.render(scene, camera);
    };

    // Run game logic (update, render, repeat)
    var gameLoop = function() {
      requestAnimationFrame(gameLoop);
      update();
      render();
    };
    gameLoop();
  }

  /**** Basic Scene Setup ****/
  function initScene() {
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xd3d3d3);
    var axis = new THREE.AxesHelper();
    scene.add(axis);
  }

  function addCamera() {
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(3, 3, 3);
    scene.add(camera);
  }

  function addGridHelper() {
    var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
    planeGeometry.rotateX(-Math.PI / 2);

    var planeMaterial = new THREE.ShadowMaterial({
      opacity: 0.2
    });
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.position.y = -200;
    plane.receiveShadow = true;
    scene.add(plane);

    var helper = new THREE.GridHelper(2000, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = new THREE.AxesHelper();
    scene.add(axis);
  }

  // *********** Lighting settings **********************
  function addLighting() {
    var light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
    scene.add(light);
  }

  //************** End of materials ***************

  function addRenderer() {
    renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);
  }

  function addOrbitControls() {
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
  }

  function addPivot() {
    var cubeGeo = new THREE.BoxBufferGeometry(5, 5, 5);
    var cubeMat = new THREE.MeshBasicMaterial();
    pivot = new THREE.Mesh(cubeGeo, cubeMat);
    bagMesh.position.x -= 15;
    bagMesh.position.z -= 55;

    pivot.add(bagMesh);
    pivot.add(handle);
    scene.add(pivot);
  }
  
  function loadCubeObj() {
    loadObjWithMtl('LetterBox',
        'https://raw.githubusercontent.com/Katana24/threejs-experimentation/master/models/cube/letter-block.obj',
        'https://raw.githubusercontent.com/Katana24/threejs-experimentation/master/models/cube/letter-block.mtl')
      .then(function(mesh) {
        mesh.traverse(function(child) {
          if (child instanceof THREE.Mesh) {
            var materials = [
              new THREE.MeshBasicMaterial({
                map: new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/master/img/cube-diffuse-texture.png')
              })
            ];
            child.material = materials[0];
          }
        });
        scene.add(mesh);
      });
  }

  function loadObjWithMtl(modelName, modelUrl, mtlUrl, modificationFunc) {
    return new Promise(function(resolve, reject) {
      var callbackOnLoad = function(event) {
        var mesh = event.detail.loaderRootNode;
        if (modificationFunc) {
          modificationFunc(mesh);
          resolve(mesh);
        } else {
          resolve(mesh);
        }
      };
      var onLoadMtl = function(materials) {
        objLoader.setModelName(modelName);
        objLoader.setMaterials(materials);
        objLoader.getLogger().setDebug(true);
        objLoader.load(modelUrl, callbackOnLoad, null, null, null, false);
      };
      objLoader.loadMtl(mtlUrl, null, onLoadMtl);
    });
  }

})();
body {
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}

#canvas {
  margin: 10px auto;
  width: 800px;
  height: 350px;
  margin-top: -44px;
}
<body>
  <div id="container"></div>
  <img src="https://github.com/Katana24/threejs-experimentation/blob/master/img/cube-diffuse-texture.png">

  <script src="https://threejs.org/build/three.js"></script>
  <script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
  <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
  <script src="https://threejs.org/examples/js/loaders/MTLLoader.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/LoaderSupport.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader2.js"></script>
</body>

As you can see I'm adding a single material with a texture onto the cube - great. I have several questions regarding this.

  1. How do I apply a different material to each of the outside sides? When building the model in Blender do I need to unwrap each side individually and assign a seperate material for each?
  2. Why does only a single material work?
  3. How do I apply a different material to each side, including the inside?

I'll ask a different SO question about number three as I've made a another unwrapped cube (I duplicated the sides and flipped the normals and applied different materials to the inside and outside (using Nodes) for this.), unless someone can answer it here.

I tried the following for 1:

  mesh.traverse( function (child) {
    if( child instanceof THREE.Mesh ) {
      var materials = [
        new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('img/1.jpg')}),
        new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('img/2.jpg')}),
        new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('img/3.jpg')}),
        new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('img/4.jpg')}),
        new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('img/5.jpg')}),
        new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('img/6.jpg')})
      ];
      child.material = materials;
    }
  });
  _this.scene.add(mesh);

But nothing appears at all. I also tried assigning each material the THREE.DoubleSide property but it had the same result.

EDIT

To answer my own questions:

  1. To place a different material on each side I needed to (in Blender):

    • unwrap the cube by marking the seams
    • export each individual face as a "UV Layout"
    • open the face in GIMP and fill with a colour to differentiate each face
    • go back to Blender, choose a side and create a new material
    • set the renderer type to "Cycles Renderer"
    • create a new material and call it "front" for the front side
    • select "Assign" to set it to the front
    • drag open the "Node Editor" screen and click "Use Nodes"
    • add a "Image Texture" node
    • open the "front" image we created in GIMP
    • finally in the 3D view set the view to "Texture" to see it reflected
    • repeat for all sides

This resulted in this:

(function onLoad() {
  var canvasElement;
  var width, height;
  var scene, camera;
  var renderer;
  var controls;

  var pivot;
  var bagMesh;
  var planeMesh;

  const objLoader = new THREE.OBJLoader2();
  const fileLoader = new THREE.FileLoader();
  const textureLoader = new THREE.TextureLoader();

  init();

  function init() {
    container = document.getElementById('container');
    initScene();
    addGridHelper();
    addCamera();
    addLighting();
    addRenderer();
    addOrbitControls();

    loadCubeObj();

    // Logic
    var update = function() {};

    // Draw scene
    var render = function() {
      renderer.render(scene, camera);
    };

    // Run game logic (update, render, repeat)
    var gameLoop = function() {
      requestAnimationFrame(gameLoop);
      update();
      render();
    };
    gameLoop();
  }

  /**** Basic Scene Setup ****/
  function initScene() {
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xd3d3d3);
    var axis = new THREE.AxesHelper();
    scene.add(axis);
  }

  function addCamera() {
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(3, 3, 3);
    scene.add(camera);
  }

  function addGridHelper() {
    var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
    planeGeometry.rotateX(-Math.PI / 2);

    var planeMaterial = new THREE.ShadowMaterial({
      opacity: 0.2
    });
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.position.y = -200;
    plane.receiveShadow = true;
    scene.add(plane);

    var helper = new THREE.GridHelper(2000, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = new THREE.AxesHelper();
    scene.add(axis);
  }

  // *********** Lighting settings **********************
  function addLighting() {
    var light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
    scene.add(light);
  }

  //************** End of materials ***************

  function addRenderer() {
    renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);
  }

  function addOrbitControls() {
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
  }

  function addPivot() {
    var cubeGeo = new THREE.BoxBufferGeometry(5, 5, 5);
    var cubeMat = new THREE.MeshBasicMaterial();
    pivot = new THREE.Mesh(cubeGeo, cubeMat);
    bagMesh.position.x -= 15;
    bagMesh.position.z -= 55;

    pivot.add(bagMesh);
    pivot.add(handle);
    scene.add(pivot);
  }
  
  function loadCubeObj() {
    loadObjWithMtl('LetterBox',
        'https://raw.githubusercontent.com/Katana24/threejs-experimentation/master/models/cube/cube-1.obj',
        'https://raw.githubusercontent.com/Katana24/threejs-experimentation/master/models/cube/cube-1.mtl')
      .then(function(mesh) {
        mesh.traverse(function(child) {
          if (child instanceof THREE.Mesh) {
            child.material = new THREE.MeshBasicMaterial({
                map: new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/master/models/cube/imgs/cube-1-all.png'), side: THREE.DoubleSide
              });
          }
        });
        scene.add(mesh);
      });
  }

  function loadObjWithMtl(modelName, modelUrl, mtlUrl, modificationFunc) {
    return new Promise(function(resolve, reject) {
      var callbackOnLoad = function(event) {
        var mesh = event.detail.loaderRootNode;
        if (modificationFunc) {
          modificationFunc(mesh);
          resolve(mesh);
        } else {
          resolve(mesh);
        }
      };
      var onLoadMtl = function(materials) {
        objLoader.setModelName(modelName);
        objLoader.setMaterials(materials);
        objLoader.getLogger().setDebug(true);
        objLoader.load(modelUrl, callbackOnLoad, null, null, null, false);
      };
      objLoader.loadMtl(mtlUrl, null, onLoadMtl);
    });
  }

})();
body {
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}

#canvas {
  margin: 10px auto;
  width: 800px;
  height: 350px;
  margin-top: -44px;
}
<body>
  <div id="container"></div>
  <img src="https://github.com/Katana24/threejs-experimentation/blob/master/img/cube-diffuse-texture.png">

  <script src="https://threejs.org/build/three.js"></script>
  <script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
  <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
  <script src="https://threejs.org/examples/js/loaders/MTLLoader.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/LoaderSupport.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader2.js"></script>
</body>
  1. A single material will work only if your exported model defines a single material in its construction. In my first code snippet the object had a single material exported, whereas in the second there are 5 materials that each describe a single position for that side which allows each to be changed.

3.To apply a different material to each side including the inside is the same process as described in 1 but you have to duplicate all the sides and flip the normals before assigning materials.

EDIT 2

In my latest code snippet above, if I change from the image that I exported from GIMP that covers everything and just load some random images they don't appear on the cube correctly:

enter image description here

How do I map the texture correctly to appear on each side without part of the image moving off to one side or the other?

Thanks

1
Read about groups of THREE.BufferGeometry() and how it works, for example, for THREE.BoxBufferGeometry()prisoner849
@prisoner849 will do. Though shortly after posting this I answered some of my own questionsKatana24

1 Answers

0
votes

Ok so after some amount of messing around I figured it all out. To answer my last question (see EDIT 2) I did have to duplicate all the sides and flip the normals for the insides.

But what should be noted here is that when you apply a material to each side of the cube, including the inside and assign an image to that material it will look good in threejs.

For example:

enter image description here

is a cube with UV mapping all done in Blender. But when applied to other images it resulted in a cube similar to the image in Edit 2.

To correct this I needed to manually modify the vt values in the .obj file. I won't bother posting the original .obj here so expand the code snippet below and check it out on my git. (I'll keep a StackOverflow branch going so it wont get modified)

(function onLoad() {
  var canvasElement;
  var width, height;
  var scene, camera;
  var renderer;
  var controls;

  var pivot;
  var bagMesh;
  var planeMesh;

  const objLoader = new THREE.OBJLoader2();
  const fileLoader = new THREE.FileLoader();
  const textureLoader = new THREE.TextureLoader();

  init();

  function init() {
    container = document.getElementById('container');
    initScene();
    addGridHelper();
    addCamera();
    addLighting();
    addRenderer();
    addOrbitControls();

    loadCubeObj();

    // Logic
    var update = function() {};

    // Draw scene
    var render = function() {
      renderer.render(scene, camera);
    };

    // Run game logic (update, render, repeat)
    var gameLoop = function() {
      requestAnimationFrame(gameLoop);
      update();
      render();
    };
    gameLoop();
  }

  /**** Basic Scene Setup ****/
  function initScene() {
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xd3d3d3);
    var axis = new THREE.AxesHelper();
    scene.add(axis);
  }

  function addCamera() {
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(3, 3, 3);
    scene.add(camera);
  }

  function addGridHelper() {
    var planeGeometry = new THREE.PlaneGeometry(2000, 2000);
    planeGeometry.rotateX(-Math.PI / 2);

    var planeMaterial = new THREE.ShadowMaterial({
      opacity: 0.2
    });
    var plane = new THREE.Mesh(planeGeometry, planeMaterial);
    plane.position.y = -200;
    plane.receiveShadow = true;
    scene.add(plane);

    var helper = new THREE.GridHelper(2000, 100);
    helper.material.opacity = 0.25;
    helper.material.transparent = true;
    scene.add(helper);

    var axis = new THREE.AxesHelper();
    scene.add(axis);
  }

  // *********** Lighting settings **********************
  function addLighting() {
    var light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
    scene.add(light);
  }

  //************** End of materials ***************

  function addRenderer() {
    renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);
  }

  function addOrbitControls() {
    var controls = new THREE.OrbitControls(camera, renderer.domElement);
  }

  function addPivot() {
    var cubeGeo = new THREE.BoxBufferGeometry(5, 5, 5);
    var cubeMat = new THREE.MeshBasicMaterial();
    pivot = new THREE.Mesh(cubeGeo, cubeMat);
    bagMesh.position.x -= 15;
    bagMesh.position.z -= 55;

    pivot.add(bagMesh);
    pivot.add(handle);
    scene.add(pivot);
  }

  function loadCubeObj() {
    loadObjWithMtl('LetterBox',
        'https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/models/cube/cube-3.obj',
        'https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/models/cube/cube-3.mtl')
      .then(function(mesh) {
        mesh.traverse(function(child) {
          var textures = [
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/1.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/2.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/3.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/4.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/5.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/4.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/3.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/2.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/1.jpg'),
            new THREE.TextureLoader().load('https://raw.githubusercontent.com/Katana24/threejs-experimentation/stack-overflow/img/2.jpg')
          ];
          if( child instanceof THREE.Mesh ) {
            for(var i = 0; i < 10; i++) {
                child.material[i] = new THREE.MeshBasicMaterial({map: textures[i]});	
            }
          }
        });
        scene.add(mesh);
      });
  }
  
  function getRandomColour() {
		return "#000000".replace(/0/g,function(){return (~~(Math.random()*16)).toString(16);});
	}	

  function loadObjWithMtl(modelName, modelUrl, mtlUrl, modificationFunc) {
    return new Promise(function(resolve, reject) {
      var callbackOnLoad = function(event) {
        var mesh = event.detail.loaderRootNode;
        if (modificationFunc) {
          modificationFunc(mesh);
          resolve(mesh);
        } else {
          resolve(mesh);
        }
      };
      var onLoadMtl = function(materials) {
        objLoader.setModelName(modelName);
        objLoader.setMaterials(materials);
        objLoader.getLogger().setDebug(true);
        objLoader.load(modelUrl, callbackOnLoad, null, null, null, false);
      };
      objLoader.loadMtl(mtlUrl, null, onLoadMtl);
    });
  }

})();
body {
  background: transparent;
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}

#canvas {
  margin: 10px auto;
  width: 800px;
  height: 350px;
  margin-top: -44px;
}
<body>
  <div id="container"></div>
  <img src="https://github.com/Katana24/threejs-experimentation/blob/master/img/cube-diffuse-texture.png">

  <script src="https://threejs.org/build/three.js"></script>
  <script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>
  <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
  <script src="https://threejs.org/examples/js/loaders/MTLLoader.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/LoaderSupport.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/loaders/OBJLoader2.js"></script>
</body>