前端开发
React Three Fiber 场景交互实现:指针拾取…
在 React Three Fiber 中实现对象选择、拖拽、键盘移动和相机控制等场景交互时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
React Three Fiber 场景通用
解决思路
- 先检查已安装的 Fiber、Drei 和输入库版本;示例面向 Fiber 9 / React 19。在连接处理器之前,先确定相机移动、对象移动和 UI 输入各自的归属。
- 将可选对象挂载在 Canvas 之下;重要操作保留 Canvas 外可访问的 DOM 控件,因为仅靠 mesh 指针处理器无法提供键盘访问。
- 理解事件语义:R3F 对带处理器的对象做 raycast,按距离投递命中,然后沿祖先冒泡;event.object 是命中对象,event.eventObject 是拥有处理器的对象。
- 用 stopPropagation() 阻止事件投递给更远的命中和祖先;它改变事件投递,但不避免已执行的 raycast,调用它可能立即对命中后方先前悬停的对象触发 pointerout。
- event.point 是世界空间坐标;保留的值要克隆,并在赋给局部变换前转换到父级局部空间;把 2D 拖拽映射到 3D 需要平面交点或深度参考。
- 用 Canvas 的 onPointerMissed 处理背景取消选择;用事件的移动信息和应用的姿态策略区分点击与拖拽。
- 指针捕获在 R3F 中是对命中测试的补充;通过 event.target.setPointerCapture(event.pointerId) 捕获,并用对应释放方法释放,同时处理取消/丢失捕获。
- 指针静止时相机移动可能需要调用 state.events.update() 刷新悬停结果;只在需要时调用,不要每帧无条件额外 raycast。
- 对昂贵的拾取使用更简单的命中代理或图层过滤;不要仅靠视觉透明来阻止相交。
- 环绕用 OrbitControls;需要脚本化过渡和更丰富相机行为时用 CameraControls;复制 props 或方法前先检查已安装的 Drei/底层控件版本。
- Drei 控件管理帧更新和按需失效;避免在同一相机上挂载多个活动控件而不做显式协调。
- makeDefault 会把控件实例暴露给与之协调的辅助工具;TransformControls 可在拖拽时暂停默认控件,要验证自定义控件也被正确禁用/恢复。
- 对象拖拽时按所需约束选择 Drei DragControls/PivotControls/TransformControls;区分受控矩阵与自动变换,不要对同一对象同时应用两者。
- 自定义拖拽时存储初始变换、捕获指针、投影到选定平面,并在 pointerup、取消和卸载时恢复相机控件;在实际事件目标上满足 touch-action 要求。
- 共享 DOM 事件源需要与事件目标和 canvas 矩形一致的坐标前缀;测试滚动和覆盖层,盲目选择 client 坐标可能引入偏移。
- Drei KeyboardControls 提供命名动作;在 useFrame 内读取其 getter 做移动,只在离散事件时订阅并清理订阅。
- 若速度需保持恒定,归一化对角移动;视觉移动乘以 delta;对物理体,把输入发送给物理步进逻辑,而不是直接移动其 mesh。
- 在失焦时清除按住的输入,并尊重文本框焦点;指针锁定/全屏/音频可能需要显式用户手势。
- 高频指针位置用 ref,语义事件用 React state;不要仅为节流一个处理器而引入 lodash 或 store;若确需节流,清理定时器。
- ScrollControls 创建滚动上下文,useScroll 必须在其下方使用;其归一化 offset/delta 不是像素距离。
- 验证:测试重叠 mesh、嵌套 group、背景取消选择、拖出 canvas、触摸、取消、失焦和键盘替代方案;验证拖拽后相机控件能恢复。
适用边界 · 注意事项
- 不适用于动画或物理模拟本身,只用于场景交互与事件传播。
- 不要仅靠 mesh 指针处理器提供键盘可访问性,重要操作需 Canvas 外的 DOM 控件。
- 不要在同一相机上挂载多个活动控件而不做显式协调,也不要对同一对象同时应用受控矩阵与自动变换。