如何使用Three.js中的多个'.mtl'文件加载'.obj'

Krz*_*ski 5 javascript three.js

我想加载cube.obj引用多个cube_*.mtl文件的文件,后者又使用纹理图像*.png(所有资源).加载多个mtl而不是一个mtl的原因是能够动态加载具有相同几何但不同材质的对象.

我找不到这样的例子所以我试图通过加载所有mtl,创建和加载obj 来混合MultiMaterial中的示例(不再受threejs支持)文档和webgl_loader_obj_mtlMultiMaterial:

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);
});
Run Code Online (Sandbox Code Playgroud)

但这不起作用,抛出异常:

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)
Run Code Online (Sandbox Code Playgroud)

我做错了什么以及如何正确地做到这一点?

小智 0

我认为这里存在一些问题。

1) THREE.MTLLoader .load 表现为“非阻塞”函数。

因此,当 MTL 文件尚未完全加载时,您正在加载 OBJ 文件。您需要在mtlLoader.load()上作为参数传递的回调函数中加载 OBJ 文件。看看你提到的例子。

2) 关于作为参数传递的mtlLoader.load回调函数:

它的参数Materials 的类型为THREE.MTLLoader.MaterialCreator。因此,loadedMaterials是一个THREE.MTLLoader.MaterialCreator元素的数组,为了创建THREE.MultiMaterial(Three.MultiMaterial 不再受 Threejs 支持),您需要一个THREE.Material元素的数组。

此外,MultiMaterial 用于将多种材质分配给一个对象(每个对象的面一种材质),而不是用于“可选”为对象选择材质(MultiMaterial Cube 示例)。


执行此操作的一种方法(代码测试):

首先,我们需要一个LoadingManager

var manager = new THREE.LoadingManager();
Run Code Online (Sandbox Code Playgroud)

这是为了断言在加载 OBJ 之前所有 MTL 都已加载:

manager.onLoad = function() {
    /* 
       At this point, all MTL's 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);
    }
};
Run Code Online (Sandbox Code Playgroud)

我们加载所有 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);
    }); 
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你!