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

Three.js中GLTF模型Mouseover事件异常问题求助

问题排查与解决方案

嘿,我来帮你搞定这个Three.js的交互问题~你的核心问题出在事件监听的选择和状态管理的缺失上,具体原因和修复方案如下:

1. 事件类型用错了!

你现在给画布元素绑定的是mouseover和mouseout事件,这两个事件的触发逻辑是:

  • mouseover:只有当鼠标从画布外部第一次进入画布区域时才会触发
  • mouseout:只有当鼠标从画布区域移出到外部时才会触发

这就导致当鼠标已经在画布内部(比如黑色背景区域)移动到模型上时,mouseover根本不会触发,你的射线检测代码自然不会执行,也就看不到变色效果。

正确的做法是使用mousemove事件,这个事件会在鼠标在画布内每一次移动时都触发,这样才能实时检测鼠标是否悬停在模型上。

2. 缺少状态跟踪,无法正确恢复颜色

现在的代码没有记录「当前被高亮的模型」,如果鼠标从一个模型移到另一个模型,之前的模型会一直保持黄色;而且你硬编码了恢复颜色为0xff0000,但模型的原始颜色可能并不是红色,这会导致颜色恢复错误。

我们需要:

  • 一个变量跟踪当前悬停的模型
  • 在加载模型时保存每个模型的原始颜色

修正后的完整代码

const loader = new GLTFLoader();
const sceneMeshes = [];
let currentHoveredMesh = null; // 跟踪当前悬停的模型

loader.load('models/box.glb', function (gltf) {
  gltf.scene.traverse(function (child) {
    if (child.isMesh) {
      let m = child;
      m.receiveShadow = true;
      m.castShadow = true;
      m.material.flatShading = true;
      m.originalColor = m.material.color.clone(); // 保存模型原始颜色
      sceneMeshes.push(m);
    }
    if (child.isLight) {
      let l = child;
      l.castShadow = true;
      l.shadow.bias = -.003;
      l.shadow.mapSize.width = 2048;
      l.shadow.mapSize.height = 2048;
    }
  });
  scene.add(gltf.scene);
  console.log(gltf.scene);
}, (xhr) => {
  console.log((xhr.loaded / xhr.total * 100) + '% loaded');
}, (error) => {
  console.log(error);
});

const raycaster = new THREE.Raycaster();

// 替换事件监听:用mousemove实时检测,mouseleave处理离开画布的情况
renderer.domElement.addEventListener('mousemove', onMouseMove, false);
renderer.domElement.addEventListener('mouseleave', onMouseLeave, false);

function onMouseMove(event) {
  // 计算标准化鼠标坐标
  const mouse = {
    x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
    y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
  };

  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects(sceneMeshes, false);

  // 如果有相交的模型
  if (intersects.length > 0) {
    const targetMesh = intersects[0].object;
    // 如果和当前悬停的不是同一个模型,先恢复之前的模型颜色
    if (currentHoveredMesh && currentHoveredMesh !== targetMesh) {
      currentHoveredMesh.material.color.copy(currentHoveredMesh.originalColor);
    }
    // 高亮当前模型
    targetMesh.material.color.set(0xffff00);
    currentHoveredMesh = targetMesh;
  } else {
    // 没有相交模型,且之前有悬停的,恢复颜色
    if (currentHoveredMesh) {
      currentHoveredMesh.material.color.copy(currentHoveredMesh.originalColor);
      currentHoveredMesh = null;
    }
  }
}

// 处理鼠标离开画布的情况,恢复所有可能的高亮
function onMouseLeave() {
  if (currentHoveredMesh) {
    currentHoveredMesh.material.color.copy(currentHoveredMesh.originalColor);
    currentHoveredMesh = null;
  }
}

关键修复点总结

  • 用mousemove事件替代mouseover,实现鼠标在画布内移动时的实时检测
  • 新增currentHoveredMesh变量跟踪当前悬停状态,确保颜色切换正确
  • 加载模型时保存每个模型的originalColor,避免硬编码恢复颜色导致的错误
  • 添加mouseleave事件处理鼠标离开画布的场景,保证状态重置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 12:28:11