【问题标题】:three.js: Apply external texture to glTFthree.js:将外部纹理应用到 glTF
【发布时间】:2021-05-29 15:49:12
【问题描述】:

我有两个文件:“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 网格化。那根本不起作用,我得到了

未捕获的类型错误:无法读取未定义的属性“中心”

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

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

【问题讨论】:

  • 乍一看,您的代码看起来应该可以工作。当你 console.log textureLoader.load(texturePath) 时你会得到什么?
  • 它将返回Texture对象,就像this一样。

标签: javascript three.js model 3d textures


【解决方案1】:

这对我来说看起来不错,但我想知道我们是否应该传递对已加载纹理的引用。

Object3D#Traverse 不是异步的,所以我们必须同步更新材料。

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;
}

【讨论】:

  • 您需要设置texture.flipY = false,如果模型有多个网格,最好避免多次加载相同的纹理。另请注意,如果您要替换整个材质,则需要注意可能已在原始材质上启用的重要选项(vertexColors、vertexTangents、morphTargets、蒙皮)并将它们复制过来。
猜你喜欢
  • 2018-11-23
  • 2015-03-12
  • 2019-02-05
  • 2019-08-22
  • 1970-01-01
  • 2019-02-13
  • 2012-09-17
  • 2015-03-17
  • 2021-03-01
相关资源
最近更新 更多