如何为THREE.JS中的3D对象添加多张纹理?当前实现加载后对象显示为黑色
问题原因
你的代码存在多处逻辑错误,直接导致纹理渲染异常:
- 材质赋值逻辑错误:对每个Mesh循环7次覆盖材质,最终所有Mesh都会被强制赋值第7张纹理,完全无法匹配模型不同部位对应的纹理需求
- 缺少场景光源:
MeshPhongMaterial是依赖光照反射显示的材质,你的场景未添加任何光源,材质无法接收光照自然渲染为全黑 - GLTF纹理适配缺失:GLTF模型的纹理Y轴方向和Three.js默认加载规则相反,未手动调整会导致纹理显示错乱
- 纹理异步加载隐患:直接在材质参数内调用纹理加载方法,可能出现纹理未加载完成就渲染的异常
修复方案
- 给场景添加基础环境光和平行光,保证材质可以正常接收光照
- 修正材质赋值逻辑,按模型Mesh的顺序/名称对应分配纹理,不要循环覆盖
- 给所有加载的纹理设置
flipY = false适配GLTF的纹理坐标规则 - 提前预加载所有纹理,避免异步加载导致的渲染异常
修正后参考代码
let loaderCar = new THREE.GLTFLoader(); var textureLoader = new THREE.TextureLoader(); var car; // 1. 新增场景光源,必须添加 const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); directionalLight.position.set(10, 10, 10); scene.add(directionalLight); // 2. 预加载所有纹理,适配GLTF规则 const textures = []; for (let i = 1; i < 8; i++) { const tex = textureLoader.load(`/Cars/E30/textures1/${i}.png`); tex.flipY = false; textures.push(tex); } loaderCar.load('/Cars/E30/scene.gltf', function (gltf) { car = gltf.scene; let meshIndex = 0; car.traverse(function (node) { if (node.isMesh && meshIndex < textures.length) { // 3. 按顺序给每个Mesh分配对应纹理,不要循环覆盖 node.material = new THREE.MeshPhongMaterial({ map: textures[meshIndex] }); meshIndex++; // 如果你的模型Mesh有固定名称,建议按名称匹配纹理更准确,示例: // if (node.name === 'body') node.material.map = textures[0]; } }); scene.add(gltf.scene); }); scene.background = new THREE.Color(0xffffff); camera.position.set(0, 0, 10); function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate();
可选排查项
如果修复后仍有异常,可以做如下排查:
- 打开浏览器控制台,检查纹理路径是否存在404报错
- 如果模型本身自带材质,也可以直接替换原有材质的map属性,不需要新建材质,修改示例:
node.material.map = textures[xxx]; node.material.needsUpdate = true; - 如果需要更高的GLTF材质还原度,可以用
MeshStandardMaterial代替MeshPhongMaterial,适配GLTF的PBR材质特性
内容的提问来源于stack exchange,提问作者shymano16hz
相关产品推荐
相关产品推荐

