11 Babylonjs基础入门 射线拾取

射线Ray就相当于一束光。它用于检查模型网格和细线之间在场景中的碰撞或交叉。
在上一个教程中,我们使用函数scene.pick(scene.pointerX,scene.pointerY):使用鼠标去拾取模型网格(射线从相机位置移动鼠标位置)
但本教程中,我们将实现我们从任何点和任何方法投射射线进行拾取。例如,在第三人称视角的射击游戏中:我们的子弹和障碍物之间的碰撞。
相关API:
https://doc.babylonjs.com/api/classes/babylon.ray 实现创建射线
https://doc.babylonjs.com/api/classes/babylon.scene 中的scene.pickWithRay()方法通过射线拾取模型网格。
https://doc.babylonjs.com/api/classes/babylon.pickinginfo 拾取对象的相关信息

射线拾取第一个照射到的模型网格
案例地址:点击这里
在这里插入图片描述
在案例当中,我们将红色盒子想象成射击的角色。它将持续想朝向的方向发出射线并检测哪个敌人(其它的盒子)被击中。因此,使用鼠标你无须点击,只需要在场景中移动,红色盒子就会改变朝向。被击中的盒子高度会增加。
射线在创建时需要:起点,方向,以及长度。
首先,我们将我们将红色盒子的box.isPickable设置为false以避免红色盒子与射线触发拾取。因为我们将射线的起点设置在了红色盒子的中心。并通过红色盒子的朝向设置方向向量:

var forward = new BABYLON.Vector3(0,0,1);        
forward = vecToLocal(forward, box);

var direction = forward.subtract(origin);
direction = BABYLON.Vector3.Normalize(direction);

我们设置射线的朝向和红色盒子的朝向相同。为了获得方向,我们要先获取到在盒子旋转后的Z轴坐标系在世界坐标系下的位置,然后通过此坐标减去立方体位置获得射线朝向。函数vecToLocal是将局部坐标位置(0,0,1)乘以立方体的世界变换矩阵获得世界坐标系位置。
获取到向量以后,我们设置射线起点为立方体位置,向量为计算出来的向量,射线长度为100:

var ray = new BABYLON.Ray(origin, direction, length);

最后,通过pickWithRay()函数去判断是否拾取的模型:

var hit = scene.pickWithRay(ray);

如果拾取到模型,我们就可以通过信息去做我们需要实现的功能,例如,案例中改变了立方体y轴的缩放。
如果你需要检测与红色立方体的交点,需要将box.isPickable设置为true。
案例地址:点击这里

过滤函数

它属于一个过滤器,用去设置可选择的网格。案例地址:点击这里
首先我们需要先设置一个函数:

  function predicate(mesh){
       if (mesh == box2 || mesh == box){
           return false;
       }
       return true;
   }

然后,作为第二个参数设置pickWithRay函数:

scene.pickWithRay(ray, predicate);

有了这个参数,我们就不用对每个网格设置isPickable为false。在函数中看到,我们不仅禁掉了红色立方体,还禁掉了离得近的蓝色立方体。

最后,pickWithRay方法还有第三个参数fastCheck(可选)。它是一个布尔值(默认值为false)。如果设置为true,射线将不会按照距离射线起点最短距离返回值,而是按照场景的网格数组,返回最先匹配的那个网格。

三角面过滤函数

从Babylon.js v4.0版本开始,你可以定义一个自定义回调,以过滤选择要进行拾取的三角形面。需要的值为面的三个顶点和拾取射线:

scene.pick(scene.pointerX, scene.pointerY, null, false, null, (p0, p1, p2, ray) => {
    var p0p1 = p0.subtract(p1);
    var p2p1 = p2.subtract(p1);
    var normal = BABYLON.Vector3.Cross(p0p1, p2p1); //获取两个向量并叉乘计算面的朝向
    return (BABYLON.Vector3.Dot(ray.direction, normal) < 0);
  });

在这个案例中,我们过滤掉了所有面的向量不朝向相机的三角形。案例地址:点击这里

拾取多个

如果我们希望将射线穿过的模型都查找出来,可以使用scene.multiPickWithRay方法进行拾取, 案例地址:点击这里
在这里插入图片描述
案例中我们会发现,两个蓝色立方体会一起变高。这种返回的值将会是以pickResult组成数组,所以我们需要遍历一下进行设置。
另一种方法是直接使用Ray类。
将射线修改为局部空间坐标系:

Ray.Transform(ray, matrix) → Ray

然后使用射线的intersectsMesh方法检测:

Ray.intersectsMesh(mesh, fastCheck) //返回 PickingInfo

//射线辅助器
要了解射线的开始位置和方向是否正确,可能很难知道。为了方便调试,Babylon.js增加RayHelper。
你可以使用静态函数来创建和显示一个:

BABYLON.RayHelper.CreateAndShow(ray, scene, new BABYLON.Color3(1, 1, 0.1));

或者你可以使用另一种:

var rayHelper = new BABYLON.RayHelper(ray);
rayHelper.show(scene);

RayHelper也可以绑定到模型网格来跟踪它的方向:

var localMeshDirection = new BABYLON.Vector3(0, 0, -1);
var localMeshOrigin = new BABYLON.Vector3(0, 0, -.4);
var length = 3;
rayHelper.attachToMesh(box, localMeshDirection, localMeshOrigin, length);

查看案例:点击这里

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值