ThreeJS光线投射(Raycaster)计算鼠标点击物体(拾取)

1,565 阅读2分钟

在三维空间中计算鼠标点击了哪个物体,其实就是从点击的那个点开始发出一条射线,看这条线穿过了哪些物体。

在此之前先来熟悉一下三维空间的坐标系,在threeJs中使用的是右手坐标系,屏幕的中心点为原点。坐标取值范围是: -1到1。


平时的页面都是二维坐标,是以左上角为原点。并且坐标取值范围是按照屏幕大小的实际像素位置来获取(x, y)。


熟悉了坐标后下面看怎么在三维空间中计算鼠标点击了哪个物体,大体上分为四个步骤。

1. 获取点击时的坐标位置(x1, y1),这里是二维画面中的坐标位置。

2. 把上面(x1, y1)转换到在三维坐标的位置(x2, y2),这里(x2, y2)的还是二维里的坐标位置,只不过是以屏 幕中心为原点的位置计算。

3. 把(x2, y2)做归一化处理得到(x3, y3),因为三维坐标的取值范围是-1到1。

4. 利用ThreeJs中的Raycaster射线来获取以当前这个点开始的射线所穿过的物体。


下面开始计算过程:

步骤1: 获取到鼠标点击位置event.clientX, event.clientY 计作(x1, y1)

步骤2:  x2 = x1 - (innerWidth / 2)y2 = (innerHeight / 2) - y1 二维坐标的Y轴和三维Y轴方向相反,这里要 - y1。

步骤3: x3计算如图:

1642850382936.jpg


y3计算如图:

1642851379970.jpg

步骤4:

 // Raycaster射线拾取
 const rayRaster = new THREE.Raycaster();
 const mouse = new THREE.Vector2();

 function onClick(event) {
 
     // 计算坐标,直接把公式拿过来使用
     mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
     mouse.y = 1 - (event.clientY / window.innerHeight) * 2;
     
     // 射线
     rayRaster.setFromCamera(mouse, camera);
     
     // 射线穿过的物体,也就是点中的物体
     // 返回一个数组,所有点击到的物体集合
     const intersects = rayRaster.intersectObjects(Scene.children);
     
     // 如果有length说明射线穿过了某些物体,一般取第一个即可(看具体需求)
     if (intersects.length) {
         console.log(intersects[0]);
     }
 }
 
 document.body.addEventListener('click', onClick, false);

以上就是光线投射(Raycaster)计算鼠标点击物体的整个过程。

本文demo代码地址