Search code examples
javascriptthree.jsgeometrytexturescollada

Three.js - Load Collada file (and textures) from file inputs


Currently, I have 2 inputs, one for the geometry (.dae) file, and one for textures (.png/.jpg). I'm trying to load the Collada file with those textures from the file inputs. I have 2 functions which are called when the file inputs change:

  • loadCollada(): uses THREE.ColladaLoader to load the geometry when the geometry file input changes, and stores the geometry in a global variable called loadedCollada
  • loadTextures(): uses THREE.TextureLoader to load the textures when the textures file input changes, and stores the textures in a global variable called loadedTextures

After both of those are called, a third function, loadModel() is called. At the moment, I've got it working somewhat; the model ends up being displayed, but the textures are not applied correctly, and if the model's up axis is not Y_UP, it displays at the wrong angle. Here's what the code I've written for loadModel() does:

  • Extracts the geometries from loadedCollada into an array called geometries
  • Combines all geometries from the array into a single geometry (THREE.Geometry) using the THREE.GeometryUtils.merge() function
  • Creates a final mesh from the single geometry and textures in loadedTextures
  • Places the model into the scene

Any help would be much appreciated for this; I've been trying to figure it out for quite some time. It would be alright if I didn't have to load the Collada files from the user's machine, but I have to somehow get it to work from file inputs. Thanks :)


Solution

  • I have recently been doing the same type of thing with OBJ+MTL files from user file input.

    This addition to three.js (r88) https://github.com/mrdoob/three.js/pull/11259 allows you to override resource URLs (which will be selected from file upload).

    I also saw this example https://github.com/mrdoob/three.js/pull/12591 that I used to help me solve loading OBJ+MTL files and it should work for most model loaders, providing they use the loadingManager. This also makes it possible to just use one file input and to select the model/textures at the same time (so it can also support drag and drop).

    Therefore I made a fiddle based on the above example for collada format: https://jsfiddle.net/Lhrvna7a/45/

    The relevant parts are:

    $('.inputfile').change(function (e) {
    
    var files = e.currentTarget.files;
    var dae_path;
    
    var extraFiles = {}, file;
    for (var i = 0; i < files.length; i++) {
      file = files[i];
      extraFiles[file.name] = file;
    
     //Filename ends in .dae/.DAE
      if (files[i].name.match(/\w*.dae\b/i)) {
        dae_path = files[i].name;
      }
    }
    
    const manager = new THREE.LoadingManager();
    manager.setURLModifier(function (url, path) {       
    
      url = url.split('/');
      url = url[url.length - 1];
    
      if (extraFiles[url] !== undefined) {
    
        var blobURL = URL.createObjectURL(extraFiles[url]);
        console.log(blobURL); //Blob location created from files selected from file input
        return blobURL;     
    
      }
      return url;
    });
    
    var loader = new THREE.ColladaLoader(manager);
    loader.load(dae_path, function (collada) {
    
      console.log(collada);
      var dae = collada.scene;
    
      scene.add(dae);
    
    });                 
      });
    }   
    

    Once the model is loaded I assume the other things you mention such as merging can be performed the same as they would when loading a model normally.

    As for the model angle/orientation, the model may have been created in a software that uses a different coordinate system to three.js. I'm not sure it is possible to know the model's rotation beforehand in collada (maybe I am wrong in this), but it may be sufficient to set dae.rotation.set(0, 0, 0); before adding the model to the scene.

    Hopefully this is helpful to you.