You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GLTF模型无法应用FabricJS画布纹理,BoxGeometry功能正常

解决GLTF模型上FabricJS纹理不显示的问题

我明白你在开发这款盒子设计工具时碰到的棘手问题——用BoxGeometry的时候每个面都能正常加载FabricJS的纹理,但换成GLTF模型后纹理就死活不显示,这确实挺让人挠头的。结合你贴出来的代码,我帮你梳理几个大概率的问题点和对应的解决办法:

1. 先搞定加载顺序和异步处理的坑

你现在的代码里,纹理创建和材质赋值的逻辑是在GLTF加载回调之外执行的,但store.outerMesh是要等GLTF加载完成后才会被赋值的。这就导致你遍历store.outerMesh.children的时候,要么外层模型还没初始化,要么模型还没加载完全,材质根本没机会赋到Mesh上。

另外,你用new Image()加载图片后直接传image.src给TextureLoader,图片加载是异步的,搞不好图片还没加载完纹理就创建了,那纹理自然是空的。

修复方案:

把纹理创建和材质赋值的逻辑移到GLTF加载完成的回调里,确保模型已经准备好,同时用TextureLoader直接加载DataURI来避免异步问题:

loader.load(
    Store.currentModel.models[store.activeIndex].path,
    (gltf) => {
        const outer = gltf.scene.clone()
        Store.core.scene.add(gltf.scene);
        Store.core.scene.add(outer);
        
        // 阴影设置保持不变
        if (Config.shadow.enabled) {
            gltf.scene.children.forEach((mesh) => {
                mesh.traverse(child => {
                    if (child.isMesh) {
                        child.castShadow = true;
                        child.receiveShadow = true;
                    }
                });
            })
        }
        
        Store.mesh = gltf.scene;
        Store.outerMesh = outer;

        // 在这里处理纹理和材质,确保模型已加载完成
        this.materialArr = [];
        const textureLoader = new THREE.TextureLoader();
        
        // 遍历每个面的纹理数据
        for (const key in this.canvasDataURI) {
            textureLoader.load(this.canvasDataURI[key], (texture) => {
                texture.wrapS = THREE.RepeatWrapping;
                texture.wrapT = THREE.RepeatWrapping;
                texture.flipY = false;
                texture.mapping = THREE.UVMapping;
                texture.anisotropy = store.core.renderer.capabilities.getMaxAnisotropy();
                texture.needsUpdate = true;

                // 创建材质
                const material = new THREE.MeshPhongMaterial({
                    map: texture,
                    name: key,
                    transparent: true,
                    side: THREE.DoubleSide
                });
                this.materialArr.push(material);

                // 立即给对应名称的Mesh赋值材质
                this.assignMaterialToMesh(key, material);
            });
        }
    },
    // 进度和错误回调保持不变
    (xhr) => {
        console.log((xhr.loaded / xhr.total * 100) + '% loaded');
    },
    (error) => {
        console.error('An error happened', error);
    }
);

// 新增方法:根据名称给Mesh匹配材质
assignMaterialToMesh(meshName, material) {
    Store.outerMesh.traverse(child => {
        if (child.isMesh && child.name === meshName) {
            child.material = material;
            child.material.needsUpdate = true;
            child.geometry.uvsNeedUpdate = true; // 确保UV坐标更新
        }
    });
}

2. 检查GLTF模型的UV坐标是否正常

BoxGeometry的UV是默认生成好的,每个面都对应纹理的完整区域,但GLTF模型就不一定了:

  • 可能导出模型时没正确展开UV,导致纹理无法映射到面上
  • 可能多个面共享同一个UV集,导致单独赋值材质时纹理显示混乱

验证与修复:

先打印所有Mesh的UV信息,看看是否正常:

Store.outerMesh.traverse(child => {
    if (child.isMesh) {
        console.log(`Mesh ${child.name} 的UV:`, child.geometry.attributes.uv);
        // 如果UV不存在,尝试重新生成(仅适用于简单盒子模型)
        if (!child.geometry.attributes.uv) {
            child.geometry.computeUVs();
            child.geometry.uvsNeedUpdate = true;
        }
    }
});

如果是模型导出的问题,记得导出GLTF时勾选「UV展开」选项,确保每个面有独立的UV通道。

3. 确认Mesh名称和材质名称完全匹配

你用_.find(this.materialArr, { name: child.name })来匹配材质,但如果GLTF模型里Mesh的名称和你constants.sides里的side名称对不上,就会找不到对应的材质,自然看不到纹理。

验证与修复:

先打印所有Mesh的名称,确认和你canvasDataURI里的key是否一致:

Store.outerMesh.traverse(child => {
    if (child.isMesh) {
        console.log('当前Mesh名称:', child.name);
    }
});

如果名称不匹配,要么修改GLTF模型中Mesh的名称,要么调整你的constants.sides或canvasDataURI的key,确保两者完全对应。

4. 手动触发纹理和材质的更新

有时候即使纹理加载完成,也需要手动告诉Three.js要更新纹理和材质,否则渲染器可能不会读取最新的纹理数据:

  • 纹理加载完成后设置texture.needsUpdate = true;
  • 给Mesh赋值材质后,设置child.material.needsUpdate = true;和child.geometry.uvsNeedUpdate = true;
  • 如果Fabric画布内容有更新,重新生成DataURI后,找到对应的纹理再设置一次texture.needsUpdate = true;,不用重新创建材质

5. 检查外层盒子的可见性和层级

你克隆了GLTF场景作为外层盒子用于绘图,要确保外层盒子的visible属性是true,而且没有被原始模型遮挡。可以暂时隐藏原始模型测试一下:

gltf.scene.visible = false; // 测试时隐藏原始模型
Store.core.scene.add(outer);
outer.visible = true;

按照上面的步骤排查和修复,应该能解决GLTF模型上FabricJS纹理不显示的问题。如果还有问题,可以看看控制台有没有报错,或者补充一下模型的导出细节。

内容的提问来源于stack exchange,提问作者Rohit Bhirud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 15:47:57