Three.js中实现几何体悬停与选中状态效果的最优方案
单OutlinePass实现三种交互状态的最优方案
不用两个OutlinePass,核心思路是复用单个OutlinePass,通过动态切换目标对象数组和修改轮廓参数(比如是否启用patternTexture)来区分正常、悬停、选中三种状态,具体实现步骤如下:
1. 初始化基础配置
只创建一个OutlinePass,默认不显示轮廓(对应正常状态),同时维护两个数组分别记录悬停和选中的对象:
// 初始化OutlinePass const outlinePass = new THREE.OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera); // 默认无目标对象,不显示轮廓 outlinePass.selectedObjects = []; // 保存patternTexture,后续按需启用 const patternTexture = new THREE.TextureLoader().load('你的纹理路径'); // 维护状态数组 let hoverObjects = []; let selectedObjects = []; // 将OutlinePass添加到后期处理管道 composer.addPass(outlinePass);
2. 处理交互事件
用Raycaster实现悬停和选中的对象检测:
const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); // 鼠标移动事件 - 检测悬停对象 window.addEventListener('mousemove', (event) => { mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const intersects = raycaster.intersectObjects(scene.children, true); // 更新悬停数组:只保留第一个相交对象(如果有) hoverObjects = intersects.length > 0 ? [intersects[0].object] : []; }); // 点击事件 - 切换选中状态 window.addEventListener('click', () => { if (hoverObjects.length === 0) return; const target = hoverObjects[0]; const index = selectedObjects.findIndex(obj => obj === target); if (index > -1) { // 已选中则取消 selectedObjects.splice(index, 1); } else { // 未选中则添加 selectedObjects.push(target); } });
3. 每帧动态更新OutlinePass状态
在render循环中,根据选中/悬停的优先级(选中 > 悬停 > 正常)修改OutlinePass的参数:
function render() { requestAnimationFrame(render); // 状态优先级判断 if (selectedObjects.length > 0) { // 选中状态:启用pattern纹理,目标设为选中对象 outlinePass.selectedObjects = selectedObjects; outlinePass.patternTexture = patternTexture; outlinePass.visibleEdgeColor.set('#ff0000'); // 可自定义选中轮廓颜色 } else if (hoverObjects.length > 0) { // 悬停状态:关闭pattern纹理,目标设为悬停对象 outlinePass.selectedObjects = hoverObjects; outlinePass.patternTexture = null; outlinePass.visibleEdgeColor.set('#00ff00'); // 可自定义悬停轮廓颜色 } else { // 正常状态:无目标对象,不显示轮廓 outlinePass.selectedObjects = []; } composer.render(); } render();
方案优势
- 避免了两个OutlinePass带来的额外渲染开销,减少GPU和内存占用
- 逻辑集中,状态切换更可控,后期维护成本更低
- 可以灵活调整不同状态的轮廓颜色、纹理等参数,扩展性强
内容的提问来源于stack exchange,提问作者Gangula
相关产品推荐
相关产品推荐

