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

THREE.Object3D.add错误求助:非THREE.Object3D实例问题排查

THREE.Object3D.add 错误排查与解决

问题详情

  • 编程新手,跟着YouTube教程学习Three.js,出现错误:THREE.Object3D.add: object not an instance of THREE.Object3D
  • 已3年未接触编程,跟着教程操作仍有难度,调试后无法解决问题
  • 查帖得知常见方案是导入时添加.scene,但不确定是Resources.js的问题还是整体代码错误

附相关代码与截图

Resources.js 代码

import * as THREE from "three";

import { EventEmitter } from "events";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
import Experience from "../Experience.js";

export default class Resources extends EventEmitter{
    constructor(assets){
        super();
        this.experience = new Experience();
        this.renderer = this.experience.renderer;

        this.assets = assets;

        this.items = {};
        this.queue = this.assets.length;
        this.loaded = 0;

        this.setLoaders();
        this.startLoading();
    }

    setLoaders() {
        this.loaders = {};
        this.loaders.gltfLoader = new GLTFLoader();
        this.loaders.dracoLoader = new DRACOLoader();
        this.loaders.dracoLoader.setDecoderPath("/draco/");
        this.loaders.gltfLoader.setDRACOLoader(this.loaders.dracoLoader);
    }
    startLoading() {
        for (const asset of this.assets){
            if(asset.type === "glbModel") {
                this.loaders.gltfLoader.load(asset.path, (file)=> {
                    this.singleAssetLoaded(asset, file);
                });
            }else if (asset.type === "videoTexture"){
                this.video = {};
                this.videoTexture = {};

                this.video[asset.name] = document.createElement("video");
                this.video[asset.name].src = asset.path;
                this.video[asset.name].muted = true;
                this.video[asset.name].playsInLine = true;
                this.video[asset.name].autoplay = true;
                this.video[asset.name].loop = true;
                this.video[asset.name].play();

                this.videoTexture[asset.name] = new THREE.VideoTexture(this.video[asset.name]);

                this.videoTexture[asset.name].flipY = true;
                this.videoTexture[asset.name].minFilter = THREE.NearestFilter;
                this.videoTexture[asset.name].magFilter = THREE.NearestFilter;
                this.videoTexture[asset.name].generateMipmaps = false;
                this.videoTexture[asset.name].encoding = THREE.sRGBEncoding;

                this.singleAssetLoaded(asset, this.videoTexture[asset.name]);
            }
        }
    }

    singleAssetLoaded(asset, file) {
        this.items[asset.name] = file;
        this.loaded++;

        
        if(this.loaded === this.queue){
            this.emit("ready");
        }
    }
}

ENVIRONMENT.JS 截图

ENVIRONMENT.JS 截图

解决方案

这个错误的核心是:你尝试添加到场景/组中的对象不是Three.js的Object3D实例。结合你的代码,问题出在GLB模型的加载处理上:

  • GLTFLoader加载完成后返回的file是一个GLTF对象,只有它的.scene属性才是可添加到场景的THREE.Object3D实例
  • 你当前的代码直接把整个GLTF对象存在了this.items里,后续在Environment.js中直接用这个对象调用add,自然会触发错误

具体修改步骤

  1. 修改Resources.js中GLB模型的加载回调,传递file.scene而非整个GLTF对象:
// 原代码
this.loaders.gltfLoader.load(asset.path, (file)=> {
    this.singleAssetLoaded(asset, file);
});

// 修改后
this.loaders.gltfLoader.load(asset.path, (file)=> {
    this.singleAssetLoaded(asset, file.scene);
});
  1. 如果后续需要GLTF对象中的其他资源(比如材质、动画剪辑),可以把整个GLTF对象一起存储:
// 在singleAssetLoaded里修改存储逻辑
singleAssetLoaded(asset, file) {
    if(asset.type === "glbModel"){
        this.items[asset.name] = {
            scene: file.scene,
            gltf: file
        };
    } else {
        this.items[asset.name] = file;
    }
    this.loaded++;

    if(this.loaded === this.queue){
        this.emit("ready");
    }
}

之后在使用模型时,取xxx.scene来添加到场景即可。

  1. 同时检查Environment.js中的代码,确保你调用add方法时传入的是模型的scene对象,而非原始的GLTF加载结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 10:45:26