关于 threejs-interaction
面向实现 3D 输入、对象拾取、相机控制和选择状态的 Three.js 开发者技能。重点包括基于画布计算坐标、明确可拾取目标,以及可靠清理交互状态。
主要功能
- 01对鼠标指针或触摸输入进行射线检测
- 02配置相机与对象控制
- 03转换指针在不同空间中的坐标
- 04管理悬停与选择状态
- 05限制射线检测频率并移除监听器
适用场景
- 01通过指针或触摸选择场景对象
- 02修复偏移或缩放画布上的拾取失败
- 03添加环绕、拖动或变换交互
- 04清除过期的悬停和指针状态
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ akillness/ jeo-skills --skill threejs-interaction安装后在 Claude Code 中输入/threejs-interaction确认已加载。
附带文件SKILL.toonevals/evals.json
详细介绍
Three.js 交互
在需要直接 3D 输入、对象拾取、相机操作和选择状态时使用此技能。语义化 HTML 控件、键盘无障碍支持和焦点管理请交由
web-accessibility 处理;游戏输入架构请交由 web-game-development 处理。
何时使用此技能
- 对可选场景对象进行指针/触摸射线检测
- 添加或修复相机控制、对象拖动、变换手柄或指针锁定
- 在客户端、标准化设备、世界和屏幕坐标之间转换坐标
- 修复点击未命中、悬停状态过期、指针捕获问题或射线检测过于频繁
指令
第 1 步:定义交互边界
- 确定画布元素及其
getBoundingClientRect();当画布偏移或调整大小时,绝不能基于整个窗口对指针坐标进行标准化。 - 明确指定可拾取集合或图层。对
scene.children进行射线检测但不设边界,会意外命中目标,并随着场景变大增加开销。 - 将输入事件与视觉状态变化分开,以便独立测试和清除悬停/选择状态。
第 2 步:从实际画布发出射线
const pointer = new THREE.Vector2();
const raycaster = new THREE.Raycaster();
function pick(event) {
const rect = renderer.domElement.getBoundingClientRect();
pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
return raycaster.intersectObjects(pickables, true)[0] ?? null;
}
将嵌套命中结果解析到具有语义的可选根对象,而不要把每个子网格都作为单独的产品级目标。对画布尺寸为零的情况进行防护,并忽略画布边界以外的事件。
第 3 步:审慎选择控件和输入行为
| 要求 | 适用工具 |
|---|---|
| 绕目标旋转 | OrbitControls |
| 第一人称浏览器视角 | PointerLockControls |
| 地图/平移约束 | MapControls |
| 操作对象的变换 | TransformControls |
| 拖动已知对象 | DragControls 或显式射线平面逻辑 |
| 无障碍命令/UI 操作 | DOM 控件以及 web-accessibility |
从已安装的 Three.js 附加组件路径导入控件,并在画布/场景卸载时释放它们。不要在多个渲染循环中更新控件。
第 4 步:限制工作量并清理状态
仅在交互需要悬停时,才在指针移动时进行射线检测。对于大型场景,在考虑更复杂的加速结构之前,先使用图层、边界、宽阶段过滤或目标列表。在 pointerleave、捕获丢失、对象移除和场景拆除时清除悬停状态。
第 5 步:验证输入行为
- 测试鼠标、触摸、键盘替代操作,以及调整大小/偏移后的画布。
- 测试空白处点击、嵌套网格、被遮挡的对象,以及快速进入/离开事件。
- 确认拆除时控件会释放事件监听器,并清除指针锁定/拖动状态。
- 验证每个必须支持无指针操作的动作都具备焦点可见的 DOM 交互提示。
示例
悬停时不破坏材质
在映射表中保存每个可选对象的基准视觉状态。悬停对象变化时,先恢复旧选中对象,再应用新的高亮效果。仅当需要高亮单个网格时,避免修改共享材质颜色;应克隆材质或使用受支持的单对象信号。
将对象放置在地面上
构造一个 THREE.Plane,从指针发出射线,并使用 ray.intersectPlane。与根据屏幕坐标猜测深度相比,这种方法更可预测,且适用于任何相机。
最佳实践
- 根据画布矩形而不是
window.innerWidth和innerHeight对坐标进行标准化。 - 明确指定具有语义的拾取目标,并将子对象交点解析到根对象。
- 拖动交互应使用指针事件和指针捕获,而不是分别实现鼠标和触摸逻辑。
- 按照场景生命周期释放控件并移除自定义监听器。
- 不要将射线检测作为触发必要产品操作的唯一方式。
参考资料
评论
支持 Markdown