【three.js】23. Raycaster and Mouse Events 投射射线(碰撞检测)和鼠标事件

本文介绍了如何在Three.js中使用Raycaster技术进行光线投射,包括设置起点和方向、检测物体碰撞,以及应用到鼠标事件和模型加载中的实例。作者详细展示了如何处理动画、鼠标悬停和点击事件,以及如何在模型上实现交互效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

顾名思义,Raycaster 可以向特定方向投射(或发射)一条射线,并测试与它相交的对象。

您可以使用该技术来检测玩家前面是否有墙,测试激光枪是否击中了什么东西,测试当前鼠标下方是否有东西来模拟鼠标事件,以及许多其他事情。

设置

在我们的启动器中,我们有 3 个红色球体,我们将射出一条光线,看看这些球体是否相交。

创建光线投射器

实例化一个Raycaster

/**
 * Raycaster
 */
const raycaster = new THREE.Raycaster()

要改变光线投射的位置和方向,我们可以使用 set(...)方法。第一个参数是position,第二个参数是direction。它需要两个向量作为参数:一个是起点位置,另一个是方向。
两者都是Vector3,但direction必须进行归一化。归一化向量的长度为1. 别担心,你不必自己做数学运算,你可以调用normalize()向量上的方法:

const rayOrigin = new THREE.Vector3(- 3, 0, 0)
const rayDirection = new THREE.Vector3(10, 0, 0)
rayDirection.normalize()

raycaster.set(rayOrigin, rayDirection)

在这个例子中,起点位置是(-3, 0, 0),方向是(10, 0, 0),我们通过normalize()方法将方向向量归一化处理,使其长度为1,表示这是一个单位向量。
然后将起点位置和方向向量设置为射线的起点和方向,最后使用raycaster.set()方法将它们传递给Raycaster对象。这个射线可以用于碰撞检测或者其他的渲染相关工作。
在这里,光线位置应该从我们场景的左侧开始,方向似乎向右。我们的光线应该穿过所有球体。

投射光线

要投射光线并获得相交的对象,我们可以使用两种方法,intersectObject(...)(单数)和intersectObjects(...)(复数)。
intersectObject(...)将测试一个对象并将intersectObjects(...)测试一组对象:

const intersect = raycaster.intersectObject(object2)
console.log(intersect)

const intersects = raycaster.intersectObjects([object1, object2, object3])
console.log(intersects)

如果您查看日志,您会看到intersectObject(...)返回了一个包含一个对象的数组(可能是第二个球体)并且 intersectObjects(...)返回了一个包含三个对象的数组(可能是 3 个球体的集合)。

交集的结果

raycaster.intersectObject交集的结果始终是一个数组,即使您只测试了一个对象。那是因为一条光线可以多次穿过同一个物体。想象一个甜甜圈。光线将穿过环的第一部分,然后穿过中间的孔,然后再次穿过环的第二部分,这样交集的结果就是2个对象了。

返回数组的每一项都包含很多有用的信息:

  • distance:射线原点和碰撞点之间的距离。
  • face:几何体的哪个面被光线击中。
  • faceIndex: 那张脸的索引。
  • object: 碰撞涉及什么对象。
  • point:碰撞在 3D 空间中的确切位置的Vector3 。
  • uv:该几何体中的 UV 坐标。

使用哪个数据取决于您。如果你想测试玩家面前是否有墙,你可以测试distance的值. 如果要更改对象的颜色,可以更新 object的材质。如果你想在冲击点上显示爆炸特效,你可以在该point位置创建这个爆炸动画。

测试每一帧

目前,我们一开始只投射一条光线。如果我们想在物体移动时对其进行测试,我们必须在每一帧上进行测试。让我们为球体设置动画,并在光线与它们相交时将它们变成蓝色。
删除我们之前所做的代码,只保留 raycaster 实例化:

const raycaster = new THREE.Raycaster()

通过使用tick函数中的经过时间和经典Math.sin(...)来为球体制作动画:

const clock = new THREE.Clock()

const tick = () =>
{
   
   
    const elapsedTime = clock.getElapsedTime()

    // Animate objects
    object1.position.y = Math.sin(elapsedTime * 0.3) * 1.5
    object2.position.y = Math.sin(elapsedTime * 0.8) * 1.5
    object3.position.y = Math.sin(elapsedTime * 1.4) * 1.5

    // ...
}

004.gif
您应该看到球体以不同的频率上下波动。
现在让我们在tick函数中 像以前一样更新我们的 raycaster

const clock = new THREE.Clock()

const tick = () =>
{
   
   
    // ...

    // Cast a ray
    const rayOrigin = new THREE.Vector3(- 3, 0, 0)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值