使用Three.js异步加载GLTF模型未完全加载的问题排查
GLTF模型加载不全(部分网格缺失、纹理丢失)排查与解决
问题描述
使用Three.js加载GLTF模型时,出现左耳等部分网格不可见、纹理丢失的情况。Blender中确认模型包含6个网格,但加载后仅显示3个;日志显示数组最终有6个元素,但代码执行时仅加载了3个,后续日志才更新。已使用async/await处理加载,但问题仍存在。
相关代码
World.js
import { loadModels } from './components/birds/birds.js'; import { createCamera } from './components/camera.js'; import { createLights } from './components/lights.js'; import { createScene } from './components/scene.js'; import { createControls } from './systems/controls.js'; import { createRenderer } from './systems/renderer.js'; import { Resizer } from './systems/Resizer.js'; import { Loop } from './systems/Loop.js'; let camera; let controls; let renderer; let scene; let loop; class World { constructor(container) { camera = createCamera(); renderer = createRenderer(); scene = createScene(); loop = new Loop(camera, scene, renderer); container.append(renderer.domElement); controls = createControls(camera, renderer.domElement); const { ambientLight, mainLight } = createLights(); loop.updatables.push(controls); scene.add(ambientLight, mainLight); const resizer = new Resizer(container, camera, renderer); } render() { mainLight.position.copy(camera.position); renderer.render(scene, camera); } async init() { console.log('Initializing world'); const models = await loadModels(); console.log('Adding models to scene'); models.models.forEach((model) => { console.log(model); scene.add(model); }); //controls.target.copy(models[0].position); } start() { loop.start(); } stop() { loop.stop(); } } export { World };
loadModels函数
async function loadModels() { const loader = new GLTFLoader(); const modelData = await loader.loadAsync('https://myurl.com/cat.gltf'); const models = modelData.scene.children; console.log("Models found within source file"); console.log(models); return { models } }
解决思路与方案
1. 修复网格收集逻辑(核心问题)
原代码仅取modelData.scene.children,但GLTF模型的网格可能嵌套在父节点下,导致部分网格未被收集。改用traverse()遍历整个场景树,确保所有网格被捕获:
async function loadModels() { const loader = new GLTFLoader(); // 若模型使用DRACO压缩,需引入DRACOLoader并配置路径 // const dracoLoader = new DRACOLoader(); // dracoLoader.setDecoderPath('/draco/'); // loader.setDRACOLoader(dracoLoader); const modelData = await loader.loadAsync('你的模型URL'); const models = []; // 遍历所有场景对象,仅收集网格类型 modelData.scene.traverse((obj) => { if (obj.isMesh) { // 强制关闭背面剔除,解决法线方向导致的不可见问题 obj.material.side = THREE.DoubleSide; models.push(obj); } }); console.log("收集到的网格数量:", models.length); console.log(models); return { models }; }
2. 确保资源完整加载
虽然loadAsync会等待模型文件加载,但GLTF依赖的纹理、二进制数据可能存在延迟加载问题:
- 检查模型导出设置:Blender导出GLTF时,勾选「导出所有纹理」「导出可见对象」,避免遗漏资源。
- 若使用压缩格式(如DRACO),需正确配置
DRACOLoader,确保解码器加载完成。
3. 修复显示与渲染问题
- 背面剔除问题:遍历网格时设置
obj.material.side = THREE.DoubleSide,强制渲染正反两面,排除法线方向错误导致的不可见。 - 纹理丢失:遍历材质时检查
map属性,若缺失可设置默认材质:if (!obj.material.map) { obj.material.map = new THREE.Texture(); // 或使用纯色材质 }
4. 同步初始化与渲染流程
确保模型加载完成后再启动渲染循环,可修改init()函数:
async init() { console.log('Initializing world'); const models = await loadModels(); console.log('Adding models to scene'); models.models.forEach((model) => scene.add(model)); // 模型加载完成后再启动循环 this.start(); }
额外排查点
- 检查相机位置与视野:确保相机能覆盖所有模型,避免部分网格在视锥体之外。
- 检查灯光设置:添加足够的光源,避免因光照不足导致模型不可见。
内容的提问来源于stack exchange,提问作者nathan lachenmyer
相关产品推荐
相关产品推荐

