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

使用Three.js加载OBJ模型时网格显示黑色的问题求助

解决Three.js加载OBJ+MTL模型显示黑色的问题

模型显示黑色大概率是纹理未正确加载或者灯光配置时机有问题,给你几个针对性的修改方案:

1. 修正MTL纹理路径

MTL文件里的纹理路径是相对MTL文件本身的,但默认MTLLoader会以当前页面为基准查找纹理,所以需要设置setPath指定纹理的基准目录:

const mtlLoader = new MTLLoader();
mtlLoader.setPath('House/v2/'); // 指向MTL和纹理所在的文件夹
mtlLoader.load('texturedMesh.mtl', function(materials) {
    // ... 原有代码
});

2. 提前添加灯光到场景

你现在是等OBJ加载完成后才添加灯光,初始渲染时场景没有灯光,模型自然变黑。把灯光代码移到加载逻辑外面:

// 把灯光放到加载代码之前,确保场景一开始就有光照
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x404040, 1);
scene.add(hemisphereLight);

// 再执行MTL和OBJ加载逻辑
const mtlLoader = new MTLLoader();
// ...

3. 验证纹理加载状态

给加载器添加进度和错误回调,同时在OBJ加载完成后遍历模型,确认材质和纹理是否正确加载:

mtlLoader.load(
    'texturedMesh.mtl',
    function(materials) {
        materials.preload();
        const objLoader = new OBJLoader();
        objLoader.setMaterials(materials);

        objLoader.load(
            'texturedMesh.obj',
            function(object) {
                // ... 原有模型缩放、添加逻辑
                // 遍历模型检查材质
                object.traverse(function(child) {
                    if (child.isMesh) {
                        console.log('Mesh材质:', child.material);
                        if (child.material.map) {
                            console.log('纹理已加载:', child.material.map);
                        } else {
                            console.log('该Mesh无绑定纹理');
                        }
                    }
                });
            },
            (xhr) => console.log(`OBJ加载进度: ${(xhr.loaded/xhr.total*100).toFixed(2)}%`),
            (err) => console.error('OBJ加载失败:', err)
        );
    },
    (xhr) => console.log(`MTL加载进度: ${(xhr.loaded/xhr.total*100).toFixed(2)}%`),
    (err) => console.error('MTL加载失败:', err)
);

完整修改后的script.js代码

import * as THREE from 'three';
import { MTLLoader } from 'MTLLoader';
import { OBJLoader } from 'OBJLoader';
import { OrbitControls } from 'OrbitControls';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x808080);
document.body.appendChild(renderer.domElement);

// 提前添加灯光,避免初始无光照渲染
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x404040, 1);
scene.add(hemisphereLight);

// 加载材质与模型
const mtlLoader = new MTLLoader();
mtlLoader.setPath('House/v2/'); // 指定MTL和纹理所在目录
mtlLoader.load(
    'texturedMesh.mtl',
    function(materials) {
        materials.preload();
        const objLoader = new OBJLoader();
        objLoader.setMaterials(materials);

        objLoader.load(
            'texturedMesh.obj',
            function(object) {
                object.scale.set(0.5, 0.5, 0.5);
                object.position.y = -1;
                scene.add(object);

                // 验证材质与纹理加载状态
                object.traverse(function(child) {
                    if (child.isMesh) {
                        console.log('当前Mesh材质:', child.material);
                        if (child.material.map) {
                            console.log('纹理状态:', child.material.map.isTexture ? '已加载' : '未加载');
                        } else {
                            console.log('该Mesh未绑定纹理');
                        }
                    }
                });

                camera.position.set(0, 0, 5);
                camera.lookAt(scene.position);

                const controls = new OrbitControls(camera, renderer.domElement);

                function animate() {
                    requestAnimationFrame(animate);
                    controls.update();
                    renderer.render(scene, camera);
                }
                animate();
            },
            (xhr) => console.log(`OBJ加载进度: ${(xhr.loaded/xhr.total*100).toFixed(2)}%`),
            (err) => console.error('OBJ加载失败:', err)
        );
    },
    (xhr) => console.log(`MTL加载进度: ${(xhr.loaded/xhr.total*100).toFixed(2)}%`),
    (err) => console.error('MTL加载失败:', err)
);

// 窗口大小调整处理
window.addEventListener('resize', function() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

另外注意检查:纹理文件名和MTL文件中指定的名称是否完全一致(包括大小写),文件名不匹配也是纹理加载失败的常见原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 13:59:40