Three.js加载多GLTF模型设为超链接及duck未定义报错解决咨询
问题解决方法
1. 解决Uncaught (in promise) TypeError: duck is undefined报错
报错原因
GLTFLoader加载模型是异步操作,两个模型的加载完成顺序不固定:如果cube模型先加载完成,会直接触发回调里的animate()函数,此时duck还未完成加载赋值,是undefined状态,直接访问duck.rotation就会抛出类型错误。同时你在两个模型的加载回调里都调用了animate(),会重复启动动画帧循环,造成性能浪费。
修复方案
修改animate函数,先判断模型对象是否存在再执行旋转逻辑,同时统一在init函数末尾调用一次animate即可:
function init() { // 原有其他逻辑不变,仅删除两个loader回调里的animate()调用 let loader = new THREE.GLTFLoader(); loader.load('./3d/duck.gltf', function(gltf){ scene.add(gltf.scene); duck = gltf.scene.children[0]; duck.position.set(0,0,0); // 删掉原有的animate()调用 }) loader.load('./3d/cube.gltf', function(gltf){ scene.add(gltf.scene); box = gltf.scene.children[0]; box.position.set(-2,0,0); // 删掉原有的animate()调用 }) // 末尾统一调用一次动画 animate(); } // 修改animate函数逻辑 function animate(){ controls.update(); // 存在对应模型才执行旋转操作 if(duck) duck.rotation.x += 0.01; if(box) box.rotation.y += 0.01; requestAnimationFrame(animate); renderer.render(scene, camera); }
如果需要更稳妥的等所有模型加载完再启动动画,可以使用THREE.LoadingManager监听所有加载任务的完成状态。
2. 3D模型添加超链接跳转功能
通过Three.js的射线检测Raycaster实现点击3D模型跳转逻辑,步骤如下:
- 给每个加载完成的模型添加自定义跳转地址属性
- 监听页面点击事件,发射射线检测点击位置是否命中3D模型
- 命中带跳转地址的模型后执行页面跳转
完整实现代码
// 先在加载模型时给模型添加跳转链接属性 loader.load('./3d/duck.gltf', function(gltf){ scene.add(gltf.scene); duck = gltf.scene.children[0]; duck.position.set(0,0,0); // 自定义跳转地址,替换为你实际需要的链接 duck.userData.link = '你的第一个跳转地址'; }) loader.load('./3d/cube.gltf', function(gltf){ scene.add(gltf.scene); box = gltf.scene.children[0]; box.position.set(-2,0,0); // 自定义跳转地址,替换为你实际需要的链接 box.userData.link = '你的第二个跳转地址'; }) // 新增射线检测相关代码 const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); function onModelClick(event) { // 转换鼠标坐标为Three.js裁剪空间坐标 mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 更新射线起点和方向 raycaster.setFromCamera(mouse, camera); // 检测射线和场景内物体的碰撞,第二个参数true代表检测所有子级物体 const intersects = raycaster.intersectObjects(scene.children, true); if(intersects.length > 0) { // 递归查找带跳转链接的父级对象,适配GLTF多层级结构 let target = intersects[0].object; while(target) { if(target.userData?.link) { // 新窗口打开链接,要当前窗口跳转改用window.location.href = target.userData.link window.open(target.userData.link, '_blank'); break; } target = target.parent; } } } // 绑定点击事件 window.addEventListener('click', onModelClick);
后续新增另外两个模型时,遵循同样的逻辑:定义对应变量、加载时赋值、添加userData.link属性、在animate函数里补全旋转逻辑即可。
内容的提问来源于stack exchange,提问作者Imnotarobot
相关产品推荐
相关产品推荐

