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

