前言

最近稍微研究了一下网页上的3D设计,其中用到了碰撞检测机制,由于首次接触这个知识点,所以只能面向百度编程,在搜索过程中,发现所有代码、方法几乎雷同,都是用到了射线检测机制,在拜读完别人的代码后,发现其中的Vector.applyMatrix4()的函数使用原因无法理解,一番百度谷歌后无果,便手动编程探究其使用原理为何。


一、Three.js是什么?

Three.js是一款即插即用的WebGL框架,在前端的3d制作中使用友好,有简略的开发文档:Three.js中文教程,开发简便,上手极快,这里有作者做的一个简单雪花特效,可拖拽和转换视角,已上传码云,链接: 雪花特效.好了,回到正轨,下面对碰撞机制中的矩阵转换进行解读。


二、使用原因分析

1.碰撞检测机制解读

这里的碰撞检测机制在上述章节中已经提到,就是射线检测机制,由于网上的代码比较片面,注释一般,这里博主简要叙述一番。代码如下:

var geo1 = new THREE.BoxGeometry(80, 80, 80)
  var material = new THREE.MeshLambertMaterial({
    color: 0xeff444
  })
  var geo2 = new THREE.BoxGeometry(80, 80, 80)
  var mesh1 = new THREE.Mesh(geo1, material)
  var mesh2 = new THREE.Mesh(geo2, material)
  mesh2.position.x = 200

首先生成两个正方体,mesh1和mesh2,且第二个在第一个的右边200的位置,来为检测碰撞提供初始化位置。
射线函数的定义:

Raycaster( origin, direction, near, far ) { }
 
origin — 射线的起点向量。
direction — 射线的方向向量,应该归一化。
near — 所有返回的结果应该比 near 远。Near不能为负,默认值为0。
far — 所有返回的结果应该比 far 近。Far 不能小于 near,默认值为无穷大。

碰撞检测流程:

    var originPoint = mesh1.position.clone();
    for (var vertexIndex = 0; vertexIndex < mesh1.geometry.vertices.length; vertexIndex++) {
      // 顶点原始坐标
      var localVertex = mesh1.geometry.vertices[vertexIndex].clone();
      // 顶点经过变换后的坐标
      var globalVertex = localVertex.applyMatrix4(mesh1.matrix);
      // 获得由中心指向顶点的向量
      var directionVector = globalVertex.sub(mesh1.position);
      // 将方向向量初始化,并发射光线
      var ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
      // 检测射线与多个物体的相交情况
      // 如果为true,它还检查所有后代。否则只检查该对象本身。缺省值为false
      var collisionResults = ray.intersectObjects([mesh2], true);
      // 如果返回结果不为空,且交点与射线起点的距离小于物体中心至顶点的距离,则发生了碰撞
      if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) {
        crash = true;   // crash 是一个标记变量
        alert("发生了碰撞")
      }
    }

这里的代码来自于百度搜索,简要讲一下,其中originPoint为物体中心所在的位置,顶点位置为localVertex,这段代码的目的就是检测,中心到顶点的距离是否大于中心到其他物体的距离,若成立,则发生了碰撞。var collisionResults = ray.intersectObjects([mesh2], true)函数验证是否发生了碰撞,其中输入参数必须为数组,返回值与输入数组内容相同,其顺序为从近到远。接下来,引出这篇文章所要剖析的问题。

2.对Vector.applyMatrix4()的使用原因剖析

由于博主才疏学浅,在臆想中总觉得不需要这个Vector.applyMatrix4()函数(大佬们就不要来洗刷我了,我只是想的太多,会的太少,呜呜~留下了没文化的眼泪,码在这里给新手们指引一下,同时也给自己提醒一下),认为顶点坐标与中心坐标足以得到这个指向向量,所以博主手动编辑了两个正方体,并给一个正方体设置键盘可操作位移,并在移动过程中打印localVertex和globalVertex的值来分析使用原因。

在这里插入图片描述
在这里插入图片描述
可以看到初始的localVertex.applyMatrix4(mesh1.matrix)前后的各个顶点坐标并没有变化,那是不是可以认为这个函数没有用啊,当然不是,这里操作一下,可以观察到:

在这里插入图片描述

原始坐标依然没变化,但是转化后的坐标在随着移动发生变化,这个坐标和中心坐标形成的向量才是有意义的啊,所以我们可以得知,mesh1.geometry.vertices的顶点值为初始化时的固定值,不会随位移变化,那么Vector.applyMatrix4()的使用自然显得十分必要。
可以看到碰撞检测机制在使用该函数后是成功的。

在这里插入图片描述

这里引申出一个问题,ray.intersectObjects([mesh2], true)函数的检测是否相交机制是检测另一个物体的初始化顶点值还是经过Vector.applyMatrix4()之后的顶点值?读者可以自行检测一下,方法就是使另一个物体移动,发出射线检测的物体不动,看碰撞后是否能检测到碰撞。结果是不能,说明该函数只能检测和不动的物体是否碰撞,无法检测和移动的物体是否碰撞。


总结

马上10.24了,就祝大家节日快乐!!!

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐