如何用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
相关产品推荐
相关产品推荐

