2
votes

Yesterday I asked this question (Uncaught TypeError: THREE.MTLLoader is not a constructor 2.0), which I thought that I had finally gotten to work, but now new questions have instead emerged:

I have installed 'three-mtl-loader' using npm, but now it seems that the object isn't visible, eventhough I can console.log my way into seeing that the object exists.

For some reason it now spits out the following error, and I guess that that is why it is not visible:

 THREE.MeshPhongMaterial: .shading has been removed. Use the boolean .flatShading instead.
 get                                @   three.js:43339
 WebGLPrograms.getParameters        @   three.js:17838
 initMaterial                       @   three.js:21734
 setProgram                         @   three.js:21929
 WebGLRenderer.renderBufferDirect   @   three.js:20964
 renderObject                       @   three.js:21722
 renderObjects                      @   three.js:21695
 WebGLRenderer.render               @   three.js:21463
 render                             @   main.ts:163
 requestAnimationFrame (async)      
 render                             @   main.ts:162 
 requestAnimationFrame (async)      
 render                             @   main.ts:162
 requestAnimationFrame (async)  
 ...    

The code as I have it now looks like this:

import * as THREE from 'three'
import * as OBJLoader from 'three-obj-loader'
OBJLoader(THREE)
import * as MTLLoader from 'three-mtl-loader'

//create global variables such that we can work with models outside of loader: 
var model1, model2;

var mtlLoader = new MTLLoader();
mtlLoader.setPath( 'http://blabla/objects/' );
mtlLoader.load( 'bla.obj.mtl', function(materials){

  materials.preload();

  var objLoader = new THREE.OBJLoader();  
  objLoader.setMaterials( materials );
  objLoader.setPath( 'http://blabla/objects/' );
  objLoader.load( 'bla.obj', function (object){

      var object1 = object.clone();
      model1 = object;     //save in global variables and add those to the scene
      model2 = object1; 

      scene.add(model1);
      scene.add(model2)

  });
});

I am not quite sure whether it is a problem similar to this one: https://github.com/sohamkamani/three-object-loader/issues/9, because if I e.g. insert:

 let child;
 for(let i = 0; i < object.children.length; i++) {
    child = object.children[i];
    scene.add(new THREE.Mesh(child.geometry, new THREE.MeshPhongMaterial({ })));
}

A white mesh is inserted - but I wouldn't know how to insert the mtl-file as color, because in the example they use getHex(). And it also seems like something that would take a long time, if I would have to do it for each mesh individually (I am cloning the model because I need two). Or could I in some way use object.traverse - I don't want to manually change the loader.

Any help is very appreciated :D

EDIT I have now tried many different approaches, with non of them working just yet, so I will sum up the issues here, hoping that someone can see what it wrong:

  1. The approach mentioned above, and it is explained why it doesn't work in the comments. I updated to the newest version of three, and now I get the same error but only as a warning, and the objects are still not visible. The error seems to come from something else now. If I change it to flatshading in the OBJloader the warning disappear but the objects are still not visible - and I really don't want to change the files.

    THREE.MeshPhongMaterial: .shading has been removed. Use the boolean .flatShading instead
    set @   three.js:43344
    parse   @   index.js:628
    (anonymous) @   index.js:58
    (anonymous) @   three.js:30483
    XMLHttpRequest.send (async)     
    load    @   three.js:30563
    load    @   index.js:56
    (anonymous) @   main.ts:117
    (anonymous) @   index.js:36
    (anonymous) @   three.js:30090
    XMLHttpRequest.send (async)     
    load    @   three.js:30146
    load    @   index.js:34
    s   @   _prelude.js:1
    e   @   _prelude.js:1
    (anonymous) @   _prelude.js:1
    
  2. Only using the three-obj-loader works fine (as described here : Uncaught TypeError: THREE.MTLLoader is not a constructor)

  3. Copying the OBJLoader and MTLLoader (https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader.js and https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/MTLLoader.js) and putting them in the folder three/src/loaders and then including the following in the three.js:

    export { MTLLoader} from './loaders/MTLLoader.js' export { OBJoader} from './loaders/OBJLoader.js'

And then trying to load them like this:

import {MTLLoader} from 'three'
import {OBJLoader} from 'three'

and using them in the same way as above results in a Uncaught TypeError: THREE.MTLLoader is not a constructor and when trying to console.log(MTLLoader) or console.log(OBJLoader) they are both undefined. So I am not sure whether they are loaded correctly into the framework, as I can only find examples of loading them in html (<script src="js/loaders/OBJLoader.js"></script>).I am pretty new to typescript, so I am not sure if I should create a reference path, or how one would come about this.

The same problem occurs if I try to use OBJLoader2.

  1. The final thing I have tried to do, was to load the obj and mtl loader that is actually in three under examples, where I reference to it in the three.js file: export { OBJLoader } from '../examples/js/loaders/OBJLoader.js' but that gives the same 'not a constructor' error `
1
Can you please post the entire error you're receiving? I'd like to see where (what file) the error is coming from before venturing any guesses.TheJim01
Yes of course - 1 secsome_name
three-obj-loader is what's causing the warning (it's not an error), and three-mtl-loader is a version behind. It makes me worry what else is not up-to-date in those packages. Knowing that this package might also be behind the curve, would you please try npmjs.com/package/wwobjloader2 and let us know if it makes a difference?TheJim01
I would love to but I am not quite sure how to use it? I tried using it in a similar manner as above: import * as OBJLoader2 from 'wwobjloader2'; OBJLoader2(THREE); and then using new THREE.OBJLoader2() instead - but I get the error Uncaught ReferenceError: THREE is not defined at the first if-statement in the OBJLoader2.jssome_name
This probably means the version in npm is out of date from the one in the threejs repo :( The threejs ecosystem is not great. As a sanity check you can try copying the one from three's source and see if that works. In times like these I've had to host my own version of three libraries on npm, which isn't trivialAndy Ray

1 Answers

0
votes

A little late to the party but you can work around the need for alternative three.js loader npm packages by leveraging imports loader with webpack.

// I'm not positive that we even need to declare this `const` but I haven't tested
const THREE = require('three');

import {
  OBJLoader,
  MTLLoader
} from 'three';

require('imports-loader?THREE=three!three/examples/js/loaders/OBJLoader.js');
require('imports-loader?THREE=three!three/examples/js/loaders/MTLLoader.js');

The gist of this is that we import to satisfy TypeScript, but we require the loaders explicitly so we have an opportunity to feed them the global THREE that they need. If you run into a dependency that requires two imports, like FBXLoader, you can separate them with commas before the !path-to-file.js.

It's a little goofy but it lets us work without having to rely on custom packages that might not match your current version of three. I'm successfully using this with both MTLLoader and OBJLoader in a React app built with TypeScript 2.9.2.