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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 17:35:16