2012-07-13 117 views
32

我正在使用three.js。如何检测three.js中的碰撞?

我的场景中有两个网格几何图形。

如果这些几何图形相交(或者如果已转换则与相交),我想将其检测为碰撞。

如何执行three.js的碰撞检测?如果three.js没有碰撞检测设施,是否还有其他库可能会与three.js结合使用?

+2

关于如何做一些与碰撞检测一样广泛的单线问题不是真正的问题,而是一个学习主题。 Google是你的朋友。 – Nate 2012-07-13 15:44:46

+2

我在谷歌搜索它,但我只发现了射线碰撞。 – eqiproo 2012-07-13 15:56:21

+4

我认为射线碰撞是要走的路... Adnan(大概)引用的CollisionUtils.js和Collisions.js文件已过时,并且不属于最近的(本文撰写时为v49)三。 js版本。 – 2012-07-13 19:14:26

回答

85

在Three.js中,utili CollisionUtils.js和Collisions.js似乎不再受支持,而mrdoob(three.js的创建者)自己建议更新到three.js的最新版本,并将Ray类用于此目的。接下来是解决这个问题的方法之一。

想法是这样的:假设我们想要检查一个名为“Player”的给定网格是否与包含在名为“collidableMeshList”的数组中的任何网格相交。我们可以做的是创建一系列从玩家网格坐标开始的射线(Player.position),并向玩家网格几何中的每个顶点延伸。每个Ray都有一个名为“intersectObjects”的方法,该方法返回Ray相交的对象数组,以及与这些对象中每个对象的距离(从Ray的原点开始测量)。如果与交叉点的距离小于玩家位置与几何顶点之间的距离,则碰撞发生在玩家网格的内部 - 我们可能称之为“实际”碰撞。

我已经张贴在一个工作示例:

http://stemkoski.github.io/Three.js/Collision-Detection.html

您可以移动红色线框立方体用箭头键并用W/A/S/d旋转。当它与蓝色立方体中的一个相交时,如上所述,对于每个交叉点,屏幕顶部将出现一次“击中”一词。代码的重要部分如下。

for (var vertexIndex = 0; vertexIndex < Player.geometry.vertices.length; vertexIndex++) 
{  
    var localVertex = Player.geometry.vertices[vertexIndex].clone(); 
    var globalVertex = Player.matrix.multiplyVector3(localVertex); 
    var directionVector = globalVertex.subSelf(Player.position); 

    var ray = new THREE.Ray(Player.position, directionVector.clone().normalize()); 
    var collisionResults = ray.intersectObjects(collidableMeshList); 
    if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) 
    { 
     // a collision occurred... do something... 
    } 
} 

这种方法有两个潜在的问题。 (1)当射线的原点位于网格M内时,射线与M之间不会有碰撞结果返回。 (2)对于一个小的物体(与玩家网格有关)可能在各种射线之间“滑动”,因此不会记录碰撞。减少此问题发生的两种可能方法是编写代码,使小对象创建光线并从其角度进行碰撞检测,或者在网格中包含更多顶点(例如,使用CubeGeometry(100,100,100, 20,20,20)而不是CubeGeometry(100,100,100,1,1,1)。)后一种方法可能会导致性能下降,所以我建议少用一下。

我希望其他人会用这个问题的解决方案来解决这个问题。在开发这里描述的解决方案之前,我自己努力了很长一段时间。

+4

谢谢您的详细解释!我还在努力寻找一个体面的解决方案,为我的游戏提供地形和3D对象,而你的回答给了我一些新的见解! – Nick 2012-08-25 13:13:31

+3

虽然此方法似乎测试是否有任何顶点与俯仰的中心相交,但测试所有边(连接的顶点)时速度会慢两倍,但精度为100%(?)。因此,要详细说明,您需要遍历每个面,并使顶点[n]和顶点[(n + 1)%len]得到所有边。如果我拥抱某人,他们会交叉我的位置和我的手的中心,但它们不会与我的皮肤相交,因为边缘检查会进行测试。 – Funkodebat 2013-08-10 03:59:28

+0

这是个好主意!对于100%(?)精度,我认为您需要测试两个网格中的每一个的边缘,并且您需要测试它们在两个方向上的走向,因为碰撞只能在一个方向上检测到,当射线从外部到网格的内部。确定它可能会慢一些,但是你可以通过初步的边界球半径检查来加速它。但最重要的是,我认为你的准确率可能达到100%...... – 2013-08-10 20:30:38

6

这实在是过于宽泛的一个话题在SO问题覆盖,但对于润滑网站的SEO一点的缘故,这里有几个简单的出发点:

如果你想真的简单的碰撞检测,而不是一个完整的物理引擎,然后检查了Three.js: Simple Collision Detection

如果,你想一些碰撞响应另一方面,不只是“做了A和B撞?”,看看Physijs,这是一个超级易于使用的Ammo.js包装Three.js周围

+3

您链接的demo是ray collision – eqiproo 2012-07-13 18:40:18