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

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模型跳转逻辑,步骤如下:

  1. 给每个加载完成的模型添加自定义跳转地址属性
  2. 监听页面点击事件,发射射线检测点击位置是否命中3D模型
  3. 命中带跳转地址的模型后执行页面跳转

完整实现代码

// 先在加载模型时给模型添加跳转链接属性
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 11:24:04