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

如何用Three.js关联多3D物体与列表按钮?加载报错求助

问题分析与解决方案

嘿,我一眼就看到问题所在啦!你遇到的报错 THREE.Object3D.add: object not an instance of THREE.Object3D. models/wolf.obj 本质是:你把模型的文件路径字符串当成了Three.js的3D对象,直接往场景里加——这肯定不行啊,Three.js只认THREE.Object3D的实例(比如加载后的模型对象)。

另外你的代码还有两个小坑:一是没保存加载好的模型实例,只存了路径,导致后续没法操作模型;二是if (obj = name)这里是赋值操作,不是相等判断,应该用===。

我给你改好了完整代码,还加了一些实用的细节:

<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 窗口大小适配逻辑
window.addEventListener('resize',function(){
    var width = window.innerWidth;
    var height = window.innerHeight;
    renderer.setSize(width,height);
    camera.aspect = width/height;
    camera.updateProjectionMatrix();
})

var controls = new THREE.OrbitControls(camera,renderer.domElement);
camera.position.z = 5; // 给相机一个初始位置,避免和模型重叠看不到东西

// 核心改动:用这个对象存加载好的模型,键是文件路径,值是模型实例
var loadedModels = {};
var index = 0;
var files = ['models/deer.obj','models/wolf.obj'];
var objLoader = new THREE.OBJLoader();

function loadNextFile() {
    if (index > files.length - 1) return;
    var currentFile = files[index];
    objLoader.load(currentFile, function(object) {
        // 默认先隐藏模型,点击按钮再显示(你也可以改成默认显示)
        object.visible = false;
        scene.add(object);
        // 把模型存起来,方便后续按钮操作
        loadedModels[currentFile] = object;
        
        // 创建关联按钮
        var menuItems = document.createElement('button');
        menuItems.name = currentFile;
        menuItems.innerHTML = currentFile;
        menuItems.addEventListener('click', onClick);
        rightMenu.appendChild(menuItems);

        index++;
        loadNextFile();
    }, undefined, function(error) {
        // 加个错误处理,某个模型加载失败也不影响其他的
        console.error('模型加载翻车啦:', error);
        index++;
        loadNextFile();
    });
}

function onClick(event){
    var targetFilePath = event.target.name.trim();
    // 从存储的对象里拿到对应的模型
    var model = loadedModels[targetFilePath];
    if (!model) return; // 防止找不到模型的情况

    // 点击按钮切换模型的显示/隐藏状态
    model.visible = !model.visible;

    // 如果你的需求是「点击按钮只显示当前模型,隐藏其他所有模型」,就用下面这段代替上面的一行:
    // Object.values(loadedModels).forEach(function(item) {
    //     item.visible = (item === model);
    // });
}

// 必须加渲染循环!Three.js靠这个持续渲染场景
function animate() {
    requestAnimationFrame(animate);
    controls.update(); // 更新轨道控制器
    renderer.render(scene, camera);
}
animate();

loadNextFile();
</script>

重点改动说明

  • 新增loadedModels存储模型实例:加载完模型后,把它和对应的文件路径绑定存起来,这样点击按钮时能直接找到对应的3D对象,再也不会把字符串往场景里加了。
  • 修复逻辑错误:去掉了原代码里错误的赋值判断,改用直接查找模型的方式,逻辑更清晰。
  • 添加渲染循环:原代码没写requestAnimationFrame循环,Three.js场景必须持续渲染才能显示内容,这个是必加的。
  • 相机初始位置:默认相机在原点,容易和模型重叠看不到东西,给它设个z轴位置拉开距离。
  • 错误处理:加了加载失败的回调,避免一个模型加载失败导致整个加载流程卡住。
  • 高效控制显示:用模型的visible属性切换显示状态,比反复add/remove更高效,这也是Three.js的标准做法。

内容的提问来源于stack exchange,提问作者Bun Béo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 18:37:42