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

Three.js批量加载GLB模型时旋转报错及材质丢失问题求助

Three.js批量加载GLB模型时旋转报错及材质丢失问题求助

嘿,刚看了你的问题,作为Three.js新手遇到这俩问题太正常了,我来帮你拆解下:

一、旋转报错的根源和解决办法

你碰到的Uncaught TypeError: Cannot read properties of undefined (reading 'rotation'),核心原因是GLTFLoader加载模型是异步的!你的animate函数一启动就开始循环执行,但这时候GLB模型还在加载中,scene.children里根本还没模型对象,自然读不到rotation属性。后来有一个模型能转,是因为那个模型刚好在某一帧加载完成了,这时候scene.children里才有它,代码就生效了,是不是挺坑的😂

给你两个实用的解决思路:

1. 用单独数组存加载好的模型,动画里判断后操作

别直接依赖scene.children,自己搞个数组存加载完成的模型,动画里只对已加载的模型操作:

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const canvas = document.querySelector('#frontPageCanvas');
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

const renderer = new THREE.WebGLRenderer({canvas, antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor( 0xffffff, 0);

// 新增数组专门存加载好的模型
const loadedModels = [];

function loadFiles(capsulesFiles, scene) {
  const capsuleloader = new GLTFLoader();
  capsulesFiles.forEach((capsulesFile) => {
    capsuleloader.load(capsulesFile, (gltf) => {
      const model = gltf.scene;
      scene.add(model);
      loadedModels.push(model); // 加载完就塞进数组
    });
  });
 };

let capsulesFiles = ['../three.js/models/capsule_1.glb', '../three.js/models/capsule_1.glb'];
loadFiles(capsulesFiles, scene);

camera.position.z = 5;

function animate()  {
    requestAnimationFrame(animate);
    // 遍历数组,只处理已加载的模型
    loadedModels.forEach((model, index) => {
        if(index === 0){
            model.rotation.y += 0.05;
        } else if(index === 1){
            model.rotation.x -= 0.01;
            model.rotation.y -= 0.01;
        }
    });
    renderer.render(scene, camera);
}

animate();

2. 等所有模型加载完再启动动画

如果想等所有模型都加载好再动,可以用Promise来批量处理加载,确保动画只在所有模型就绪后才开始:

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const canvas = document.querySelector('#frontPageCanvas');
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

const renderer = new THREE.WebGLRenderer({canvas, antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor( 0xffffff, 0);

const loadedModels = [];

// 把单个模型加载改成返回Promise的函数
function loadSingleModel(filePath) {
  return new Promise((resolve, reject) => {
    const loader = new GLTFLoader();
    loader.load(filePath, (gltf) => {
      resolve(gltf.scene);
    }, undefined, (err) => {
      reject(`加载模型失败:${err}`);
    });
  });
}

let capsulesFiles = ['../three.js/models/capsule_1.glb', '../three.js/models/capsule_1.glb'];

// 批量加载所有模型,全部完成后再启动动画
Promise.all(capsulesFiles.map(file => loadSingleModel(file)))
.then(models => {
  models.forEach(model => {
    scene.add(model);
    loadedModels.push(model);
  });
  // 所有模型就绪,启动动画
  animate();
})
.catch(err => console.error(err));

camera.position.z = 5;

function animate()  {
    requestAnimationFrame(animate);
    loadedModels.forEach((model, index) => {
        if(index === 0){
            model.rotation.y += 0.05;
        } else if(index === 1){
            model.rotation.x -= 0.01;
            model.rotation.y -= 0.01;
        }
    });
    renderer.render(scene, camera);
}

二、材质/纹理丢失的排查方向

关于Maya导出GLB后材质没了的问题,我之前用Verge3D导出也踩过坑,你可以从这几点查:

  • Verge3D导出设置要盯紧
    导出时一定要勾选Embed Textures(嵌入纹理)!不然纹理文件不会打包进GLB,Three.js找不到纹理就会显示默认的灰色材质。同时确认导出选项里的材质模式,aiStandardSurface属于PBR材质,要确保Verge3D导出时启用了PBR相关的导出配置,别选成旧的材质模式。

  • Maya里的材质要做好前置检查
    先确认aiStandardSurface的玻璃、塑料材质在Maya视图里能正常显示,纹理(如果用了的话)要正确连接到材质节点的对应通道,比如玻璃的透明度通道要开启;另外检查模型的UV是否正确,UV有问题的话纹理也会显示异常甚至不显示。

  • Three.js的渲染配置要跟上
    GLB的PBR材质需要正确的颜色编码和光照,给渲染器加这两行:

    renderer.outputEncoding = THREE.sRGBEncoding;
    renderer.physicallyCorrectLights = true;
    

    别忘了给场景加光照!PBR材质没光照的话会显得像没材质,至少加个环境光和方向光:

    // 环境光
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    scene.add(ambientLight);
    // 方向光
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(5, 5, 5);
    scene.add(directionalLight);
    

备注:内容来源于stack exchange,提问作者YoNoms

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:29:33