前言
在网页开发中,我们通常使用 DOM 事件来操作 DOM 元素。但是在 canvas 画布中,如何监听用户对画布内容的 DOM 操作呢?除了常规的事件监听器外,在 three.js 中,我们还可以使用 Raycaster 来判断用户是否选中了画布中的物体。通过设置光线的起点和方向,Raycaster 可以检测到光线与画布中的物体是否相交,从而判断用户是否选中了某个物体。这种方式可以实现在 3D 环境中的交互操作,例如在模型上点击或者拖拽等。
本文通过一个小demo的实现,来阐述如何使用光线投射(raycaster)完成3D交互效果。
Raycaster(射线拾取模型)中几个重要的API
射线交叉计算(.intersectObjects()方法)
射线投射器Raycaster通过.intersectObjects()方法可以计算出来与自身射线.ray相交的网格模型。
语法:Raycaster.intersectObjects([mesh1, mesh2, mesh3])
计算射线(.setFromCamera()方法)
把鼠标单击位置坐标和相机作为.setFromCamera()方法的参数,.setFromCamera()就会计算射线投射器Raycaster的射线属性.ray,形象点说就是在点击位置创建一条射线,用来选中拾取模型对象。
//创建一个射线投射器`Raycaster`
const raycaster = new THREE.Raycaster();
//.setFromCamera()计算射线投射器`Raycaster`的射线属性.ray
// 形象点说就是在点击位置创建一条射线,用来选中拾取模型对象
raycaster.setFromCamera(new THREE.Vector2(x, y), camera);
实现过程
创建3个不同颜色的小球
// 创建三个球
const sphere1 = new THREE.Mesh(
new THREE.SphereGeometry(1, 32, 32),
new THREE.MeshBasicMaterial({
color: 0x00ff00,
})
);
sphere1.position.x = -4;
scene.add(sphere1);
const sphere2 = new THREE.Mesh(
new THREE.SphereGeometry(1, 32, 32),
new THREE.MeshBasicMaterial({
color: 0x0000ff,
})
);
scene.add(sphere2);
const sphere3 = new THREE.Mesh(
new THREE.SphereGeometry(1, 32, 32),
new THREE.MeshBasicMaterial({
color: 0xff00ff,
})
);
sphere3.position.x = 4;
scene.add(sphere3);
创建射线和鼠标向量
// 创建射线
const raycaster = new THREE.Raycaster();
// 创建鼠标向量
const mouse = new THREE.Vector2();
监听页面点击事件
- 获取到鼠标点击位置
- 将鼠标点击位置转换为标准设备坐标
- 建立一条由相机到鼠标点击位置的射线
- 通过
intersectObjects计算出与该条射线相交的模型 - 改变对相交的模型的颜色
代码如下:
window.addEventListener("click", (event) => {
console.log(event.clientX, event.clientY);
// 设置鼠标向量的x,y值
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -((event.clientY / window.innerHeight) * 2 - 1);
// console.log(mouse.x, mouse.y);
// 通过摄像机和鼠标位置更新射线
raycaster.setFromCamera(mouse, camera);
// 计算物体和射线的焦点
const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);
if (intersects.length > 0) {
// console.log(intersects[0].object);
if (intersects[0].object._isSelect) {
console.log(intersects[0].object._originColor);
intersects[0].object.material.color.set(
intersects[0].object._originColor
);
intersects[0].object._isSelect = false;
return;
}
intersects[0].object._isSelect = true;
intersects[0].object._originColor =
intersects[0].object.material.color.getHex();
intersects[0].object.material.color.set(0xff0000);
}
console.log(intersects);
});
总结
在 3D 交互中,光线投射(Raycaster)是一项常用的技术,掌握它可以提高交互效果的实现效率和质量。如有错误之处,欢迎大家指出,谢谢大家了。