three.js: 将外部纹理应用到 glTF

three.js: Apply external texture to glTF

我有两个文件:“model.gltf”和“texture.jpeg”。我想将纹理文件应用到模型并使用 three.js 渲染它,但经过 3 天的持续研究和数百次尝试,我无法让它正常工作。我在场景中设置当前对象的方法:

/**
 * SET method: Sets object in the scene (deleting previous one)
 * 
 * @author Anton Pernisch <anton@pernisch.dev>
 * @param {string} modelPath - Path to object in glTF format
 * @param {string} texturePath - Path to texture
 * @returns {boolean}
 * 
 * @todo Texture
 */
SET_Object: function(modelPath, texturePath) {
    // Clear out the scene
    for (var i = this.prodconf3_scene.children.length - 1; i >= 0; i--) { 
        obj = this.prodconf3_scene.children[i];
        this.prodconf3_scene.remove(obj); 
    }

    const modelLoader = new THREE.GLTFLoader();

    modelLoader.load(modelPath, (gltf) => {
        // HERE? apply texture from texturePath to this gltf

        this.prodconf3_obj = gltf.scene;
        this.prodconf3_scene.add(this.prodconf3_obj);
    });
    
    return true;
}

这段代码导入 glTF 很好,只是黑色。最终,我能够将 .jpeg 纹理应用于此模型,但仅此而已。这是我能得到的最好结果: here

那是通过这种方法:

/**
 * SET method: Sets current object to scene (deleting previous one)
 * 
 * @author Anton Pernisch <anton@pernisch.dev>
 * @param {string} modelPath - Path to object in glTF format
 * @param {string} texturePath - Path to texture
 * @returns {boolean}
 * 
 * @todo Texture
 */
SET_Object: function(modelPath, texturePath) {
    // Clear out the scene
    for (var i = this.prodconf3_scene.children.length - 1; i >=0 ; i--) { 
        obj = this.prodconf3_scene.children[i];
        this.prodconf3_scene.remove(obj); 
    }

    const modelLoader = new THREE.GLTFLoader();
    const textureLoader = new THREE.TextureLoader();

    modelLoader.load(modelPath, (gltf) => {
        var model = gltf.scene;
        model.traverse((o) => {
            if (o.isMesh) {
                o.material = new THREE.MeshBasicMaterial({map: textureLoader.load(texturePath)});
            }
        });

        this.prodconf3_obj = model;
        this.prodconf3_scene.add(this.prodconf3_obj);
    });
    
    return true;
}

我还尝试通过 TextureLoader 加载方法创建纹理,然后将其与 modelLoader.load 函数中的 gltf.scene 网格化。那根本不起作用,我得到了

Uncaught TypeError: Cannot read property 'center' of undefined

错误(我不确定使用 gltf.scene 作为 THREE.Mesh() 中的第一个参数)。

所以,我的问题是,在 three.js 中将纹理正确应用到 glTF 的正确和更新方法是什么?

我觉得这很好,但我想知道我们是否应该传递对已加载纹理的引用。

Object3D#Traverse 不是异步的,因此我们必须同步更新 material。

Live example.

SET_Object: async function(modelPath, texturePath) {
    // Clear out the scene
    for (let i = this.prodconf3_scene.children.length - 1; i >= 0; i--) { 
        obj = this.prodconf3_scene.children[i];
        this.prodconf3_scene.remove(obj); 
    }

    const modelLoader = new THREE.GLTFLoader();
    const textureLoader = new THREE.TextureLoader();

    // Load texture
    const texture = await textureLoader.loadAsync(texturePath);
    texture.flipY = false;

    // Load model
    const { scene: model } = await modelLoader.loadAsync(modelPath);

    // Update model
    model.traverse((o) => {
        if (o.isMesh) {
            o.material.map = texture;
            o.material.needsUpdate = true;
        }
    });

    this.prodconf3_obj = model;
    this.prodconf3_scene.add(this.prodconf3_obj);
    
    return this.prodconf3_obj;
}