GestureEvent 继承自 StateEvent,包含了手势中心点、射线等信息。Definition: GestureEvent
所有手势事件的回调参数均为 GestureEvent 类型:
import { State } from "@realsee/five";
import * as THREE from "three";
interface GestureEvent {
type: string; // 事件类型,如 "gesture.tap"
timeStamp: number; // 时间戳
target: EventTarget | null;
pointerType: 'touch' | 'pen' | 'mouse' | 'kinect';
// 手势中心点信息
center: {
x: number; // 屏幕 X 坐标
y: number; // 屏幕 Y 坐标
raycaster: THREE.Raycaster; // 从相机发出的射线(已包含坐标变换)
};
// 当前相机状态
state: State;
// 是否是用户触发(区别于代码调用)
userAction: boolean;
// 阻止默认行为
preventDefault(): void;
defaultPrevented: boolean;
}
Five 的手势系统基于 Hammer.js 封装,主要包含以下几种手势:
不同的 Mode 对手势有不同的默认响应:
| 手势 | Panorama (全景) | Mapview (模型) | 说明 |
|---|---|---|---|
| Pan | 旋转相机视角 (Look around) | 围绕模型旋转/平移相机 (Orbit/Pan) | |
| Pinch | 调整 FOV (Zoom in/out) | 调整相机距离 (Distance) | |
| Tap | 移动点位 (Move to pano) | 切换到全景 (Enter pano) | 若点击到地面/模型,Mapview 下默认无响应,除非点击到点位标记 |
| DblTap | 动画调整 FOV | 聚焦并拉近视角 (Fly to) | |
| MouseWheel | 调整 FOV | 调整相机距离 |
Five 的事件触发顺序如下:
gesture.xxx 事件。event.preventDefault(),Five 执行默认逻辑(如旋转相机、移动点位)。因此,如果你想自定义交互(例如:点击不走点,而是弹出一个框),必须调用 event.preventDefault()。
监听点击事件并打印日志:
five.on("gesture.tap", (event) => {
console.log("点击位置:", event.center.x, event.center.y);
// event.center.raycaster 可以用来做射线检测
});
这个示例展示了如何通过点击事件在场景中添加一个红色的球体,并阻止 Five 默认的点位移动行为。
import * as THREE from "three";
import { Five } from "@realsee/five";
const five = new Five();
five.on("gesture.tap", (event) => {
// 1. 阻止默认行为(防止点击地面时 Five 自动走点或切换模式)
event.preventDefault();
// 2. 获取射线
const raycaster = event.center.raycaster;
// 3. 检测与模型的碰撞
// five.model.intersectRaycaster 是 Five 提供的便捷方法,会自动检测所有可见模型
const intersects = five.model.intersectRaycaster(raycaster);
if (intersects.length > 0) {
const intersect = intersects[0];
const point = intersect.point; // 碰撞点世界坐标
console.log("点击到了模型,坐标:", point);
// 4. 创建一个小球
const geometry = new THREE.SphereGeometry(0.1, 32, 32);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const sphere = new THREE.Mesh(geometry, material);
// 5. 设置位置并添加到场景
sphere.position.copy(point);
five.scene.add(sphere);
// 强制刷新渲染,确保小球立即出现
five.needsRender = true;
} else {
console.log("未点击到任何模型");
}
});
five.on("gesture.pinch", (event) => {
// 获取当前 FOV
const currentFov = five.state.fov;
// 假设我们限制 FOV 在 80 到 100 之间
// 注意:这只是逻辑演示,Five 内部有自己的 minFov/maxFov 配置,
// 这里演示如何完全接管控制权。
if (currentFov < 80 || currentFov > 100) {
// 阻止 Five 的默认缩放
event.preventDefault();
console.log("已达到缩放极限");
}
});
["pan", "tap", "pinch", "press"].forEach(type => {
five.on(`gesture.${type}` as any, (e) => console.log(type, e));
});
five.scene.add(new THREE.ArrowHelper(raycaster.ray.direction, raycaster.ray.origin, 10, 0xff0000));
five.needsRender = true;
event.preventDefault()。event.center.x/y 是屏幕像素坐标,event.center.raycaster 已经处理了屏幕到世界的转换。直接使用 raycaster 最安全。stopPropagation 或判断 event.target。intersectRaycaster 的工作原理。tags: [手势, 点击, 拖拽, 缩放, 长按, 鼠标, 触摸, 交互控制, 自定义交互, gesture, event, interaction, tap, pan, pinch, preventDefault]