How to load '.obj' with multiple .mtl files in Three.js file

I would like to download the cube.obj file, which refers to several cube_*.mtl , which, in turn, use *.png texture images ( all resources ). The reason for loading multiple mtl instead of one is the ability to dynamically load objects with the same geometry, but with different materials.

I could not find such an example, so I tried to combine the examples in the MultiMaterial documentation and webgl_loader_obj_mtl , loading all mtl's, creating MultiMaterial and loading obj:

 var resources = 'cube/'; var materialsToLoad = [ 'cube_red.mtl', 'cube_green.mtl', 'cube_blue.mtl' ]; var loadedMaterials = []; var mtlLoader = new THREE.MTLLoader(); mtlLoader.setPath(resources); for (var i = 0; i < materialsToLoad.length; i++) { mtlLoader.load(materialsToLoad[i], function(materials) { materials.preload(); loadedMaterials.push(materials); }); } var multi = new THREE.MultiMaterial(loadedMaterials); var objLoader = new THREE.OBJLoader(); objLoader.setPath(resources); objLoader.setMaterials(multi); // #1 objLoader.load('cube.obj', function (object) { scene.add(object); }); 

But this does not work, an exception is thrown:

 Uncaught TypeError: this.materials.create is not a function at THREE.OBJLoader.parse (OBJLoader.js:684) at OBJLoader.js:50 at XMLHttpRequest.<anonymous> (three.min.js:619) 

What am I doing wrong and how to do it right?

+5
source share
1 answer

I think there are some problems here.

1) THREE.MTLLoader .load behaves like a "non-blocking" function.

Thus, you download OBJ files when MTL files are not yet fully loaded. You need to load the OBJ files inside the callback function passed as the argument to mtlLoader.load (). Take a look at the example you mentioned.

2) About the mtlLoader.load callback function passed as an argument:

His argument, materials, is of type THREE.MTLLoader.MaterialCreator . As a result, loadMaterials is an array of THREE.MTLLoader.MaterialCreator elements and to create THREE.MultiMaterial , you need an array of THREE.Material elements.

In addition, MultiMaterial is used to assign many materials to one object (one material on the face of the object), and not to "optionally" select material for the object ( Example MultiMaterial Cube ).


One approach for this (code NOT ):

First we need the LoadingManager :

 var manager = new THREE.LoadingManager(); 

This means that all MTLs were loaded before OBJ loading:

 manager.onLoad = function() { /* At this point, all MTL have been loaded. We will load an OBJ with the first material option (for example), if it exists. */ if (loadedMaterials.length > 0) { var objLoader = new THREE.OBJLoader(); objLoader.setPath(resources); objLoader.setMaterials(loadedMaterials[0]); // First material objLoader.load('cube.obj', function (object) { scene.add(object); } }; 

And we load all MTL:

 var mtlLoader = new THREE.MTLLoader(manager); mtlLoader.setPath(resources); for (var i = 0; i < materialsToLoad.length; i++) { mtlLoader.load(materialsToLoad[i], function(materials) { materials.preload(); loadedMaterials.push(materials); }); } 

Hope this helps!

0
source

Source: https://habr.com/ru/post/1263467/


All Articles