Pointer
Pointer 把 Engine Canvas 上的原生鼠标事件定位到 topmost RenderView,使用原生 Raycaster 命中 Object3D,再沿 Entity 路由同步派发。
最小用法
const off = entity.onPointer('click', (event) => {
console.log(event.targetEntity, event.intersection?.point);
event.stopPropagation();
});
// 不再需要时:
off();注册 handler 的 Entity 会自动进入对应事件族的候选索引。无需另建可拾取组件或 Pointer manager。
候选策略
entity.pointerEvents 支持继承的三态策略:
| 值 | 语义 |
|---|---|
null | 继承祖先;最终缺省为 listeners |
listeners | 有对应事件族 handler 时参与 |
auto | 即使没有 handler 也进入候选,可作为遮挡体 |
none | 当前子树从命中候选中排除 |
entity.pointerEvents = 'auto';
entity.pointerPriority = 10;winner 先比较有效 pointerPriority,再比较 raycast 距离。priority 同样从 leaf 向 World root 继承,缺省为 0。
候选 add/remove/reparent 时只维护 Set 并标脏;下一次真实 hit 才压缩嵌套 Object3D roots,避免对祖先和后代重复 raycast。
View 与 Camera
Pointer 对当前有效 View 反向扫描,选择覆盖坐标的最后一个 View,因此与渲染的视觉 topmost 规则一致。然后把 client 坐标转换成该 View 内的 NDC。
const hit = engine.pointer.hitTest(event.clientX, event.clientY);
if (hit.view !== null && hit.targetEntity !== null) {
console.log(hit.view.world, hit.pointer, hit.intersections);
}manual hitTest 不受 pointer.enabled、running 或 suspend gate 限制,但仍要求 Pointer/Engine 存活。它读取 Camera 已存储的 projection/world matrices,不调用隐式 update。
支持的事件
pointerdown pointermove pointerup pointercancel
pointerover pointerout pointerenter pointerleave
click dblclick contextmenu wheel普通事件沿 leaf → World root 冒泡。pointerenter/pointerleave 是逐节点非冒泡边界事件。stopPropagation() 停止后续 Entity,stopImmediatePropagation() 还会跳过当前 Entity 的剩余 handler。
Event 保留:
targetEntity/ 同步 handler 内可读的currentEntity;intersection/intersections;- View-local
pointer; - 原生
nativeEvent与 Engine 原生raycaster; view与 hover 的relatedEntity。
click 与 missed
click 只有 pointerdown/up 命中同一 Entity 与 View 后,后续原生 click 才会发布。dblclick 还要求连续两次 Engine click identity 一致。
const offMissed = engine.pointer.onMissed((event) => {
if (event.sourceType === 'click') {
clearSelection();
}
});missed 只用于已定位到 View 但未命中 Entity 的 click 与 contextmenu。坐标没有落入任何 View 时不会通知。
自动输入与性能
自动事件只在 Engine running、至少成功呈现过一个非零帧、Pointer enabled 且未 suspend 时接纳:
engine.pointer.enabled = false;
engine.pointer.enabled = true;
const release = engine.pointer.suspend();
// 业务交互期间暂停自动 Pointer
release();Pointer 每帧保留最新一个 pointermove,同时保证 down/up/cancel/click/dblclick 的离散顺序。wheel 只在存在 wheel demand 时安装非 passive listener。
Engine 不实现业务级拖拽 capture 或 native setPointerCapture 所有权。需要拖拽锁定、手势状态机或越界策略时由业务在 handler 中基于原生事件和 pointer.suspend() 处理。
Raycaster 配置
engine.pointer.raycaster.layers.enable(1);
engine.pointer.raycaster.params.Line!.threshold = 0.1;Pointer 公开唯一原生 Raycaster identity,方便使用 Three.js 自带的 layers/params 能力,不重复包装。
注意事项
- Object3D 与 Camera matrices 由业务在 mutation 后显式更新;
- handler 同步 fail-fast,保留事件对象异步读取
currentEntity会抛错; - destroy、World leave 等负向事实会立即取消 route 后续节点;
- UI overlay 默认应
pointer-events: none;需要交互的控件局部设为pointer-events: auto; - Pointer 是鼠标事件系统,不承诺触摸手势抽象。