经纬志
首页 / three.js / API 文档

Raycaster

先看结论

射线投射器,把一次点击或一条方向线转换成一串命中结果,是三维拾取的入口。

最后验证 2026-11-03 · three.js 0.160.0 · 更新 2026-10-28 · 引用本文
new THREE.Raycaster(origin, direction, near, far) → Raycaster

构造参数

参数默认说明
origin(0, 0, 0)射线起点,使用 setFromCamera 时会被相机位置覆盖
direction(0, 0, -1)方向向量,应归一化
near0最近命中距离,小于它的结果被忽略
farInfinity最远命中距离

属性

属性说明
ray底层的 Ray,含 origin 与 direction
near / far距离过滤范围
params.Points.threshold默认 1,点云拾取的判定半径(世界单位)
params.Line.threshold默认 1,线段拾取的判定半径
layers只检测指定图层的对象

方法

方法说明
set(origin, direction)直接写入起点与方向,方向需先归一化,否则距离与阈值判定会失真
setFromCamera(coords, camera)按归一化设备坐标生成射线,透视与正交相机都支持
intersectObject(obj, recursive, target)检测单个对象,recursive 默认 true,会连同后代一起检测
intersectObjects(list, recursive, target)检测一组对象,结果按距离升序排列

命中结果的字段

字段说明
object被命中的对象
distance起点到命中点的距离,按世界单位
point命中点的世界坐标 Vector3
face命中的三角面,含 normal 与三个顶点索引
faceIndex三角面在几何体中的序号
uv命中点在该面上的 UV 坐标
instanceId命中实例化网格时,返回具体实例编号

屏幕点击拾取

const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
const targets = [];   // 只放需要参与拾取的对象

renderer.domElement.addEventListener('pointerdown', function (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);
  const hits = raycaster.intersectObjects(targets, false);

  if (!hits.length) return;
  console.log(hits[0].object.name, hits[0].point.toArray());
});

recursive 传 false 时只检测列表里的对象本身,不会深入子节点。 拾取对象集中且结构扁平时,保持 false 能省掉大量遍历。

与地面求交

不需要真实网格参与时,直接把射线和数学平面求交,成本更低, 适合地形起伏不明显的高空视角。

const ground = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); // y = 0
const hitPoint = new THREE.Vector3();

raycaster.setFromCamera(pointer, camera);
const ok = raycaster.ray.intersectPlane(ground, hitPoint);
if (ok) marker.position.copy(hitPoint);

性能与常见坑

射线检测是 CPU 端的逐三角形计算,几万个面尚可接受, 几百万面的地形每次移动都检测就会明显卡顿。可行做法是把拾取对象限定在 少量代理几何(包围盒、粗网格),命中后再做精确计算。

点云与线段没有面积,只能靠 params.Points.threshold 与 params.Line.threshold 判断,阈值小于点距时会「点不中」, 阈值过大会一次命中一排点。

另外,拾取依赖相机的 matrixWorld 与对象的世界矩阵。 在 OrbitControls 更新后立即拾取,需要先 camera.updateMatrixWorld(),否则射线方向会落后一帧。

拾取的是几何,不是数据。命中结果只给坐标与对象引用, 要拿回要素 ID、属性表或业务字段,需要自己在 object.userData 或外部映射表里建立关联。

引用本文

经纬志(2026)。《Raycaster》。https://www.jingweizhi.com/three/api/raycaster.html(访问日期 2026-11-03)。