如何检测three.js中的碰撞?

时间:2021-12-21 03:20:03

I am using three.js.

我正在使用three.js。

I have two mesh geometries in my scene.

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

If these geometries are intersected (or would intersect if translated) I want to detect this as a collision.

如果这些几何形状相交(或者如果被翻译则相交)我想将其检测为碰撞。

How do I go about performing collision detection with three.js? If three.js does not have collision detection facilities, are there other libraries I might use in conjuction with three.js?

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

2 个解决方案

#1


90  

In Three.js, the utilities CollisionUtils.js and Collisions.js no longer seem to be supported, and mrdoob (creator of three.js) himself recommends updating to the most recent version of three.js and use the Ray class for this purpose instead. What follows is one way to go about it.

在Three.js中,似乎不再支持实用程序CollisionUtils.js和Collisions.js,并且mrdoob(three.js的创建者)自己建议更新到最新版本的three.js并使用Ray类来实现此目的代替。以下是一种解决方法。

The idea is this: let's say that we want to check if a given mesh, called "Player", intersects any meshes contained in an array called "collidableMeshList". What we can do is create a set of rays which start at the coordinates of the Player mesh (Player.position), and extend towards each vertex in the geometry of the Player mesh. Each Ray has a method called "intersectObjects" which returns an array of objects that the Ray intersected with, and the distance to each of these objects (as measured from the origin of the Ray). If the distance to an intersection is less than the distance between the Player's position and the geometry's vertex, then the collision occurred on the interior of the player's mesh -- what we would probably call an "actual" collision.

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

I have posted a working example at:

我发布了一个工作示例:

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

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

You can move the red wireframe cube with the arrow keys and rotate it with W/A/S/D. When it intersects one of the blue cubes, the word "Hit" will appear at the top of the screen once for every intersection as described above. The important part of the code is below.

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

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...
    }
}

There are two potential problems with this particular approach.

这种特殊方法存在两个潜在的问题。

(1) When the origin of the ray is within a mesh M, no collision results between the ray and M will be returned.

(1)当光线的原点在网格M内时,将不返回光线和M之间的碰撞结果。

(2) It is possible for an object that is small (in relation to the Player mesh) to "slip" between the various rays and thus no collision will be registered. Two possible approaches to reduce the chances of this problem are to write code so that the small objects create the rays and do the collision detection effort from their perspective, or include more vertices on the mesh (e.g. using CubeGeometry(100, 100, 100, 20, 20, 20) rather than CubeGeometry(100, 100, 100, 1, 1, 1).) The latter approach will probably cause a performance hit, so I recommend using it sparingly.

(2)小的(相对于玩家网格)的物体可能在各种射线之间“滑动”,因此不会记录碰撞。减少此问题几率的两种可能方法是编写代码,以便小对象创建光线并从其视角执行碰撞检测工作,或在网格上包含更多顶点(例如,使用CubeGeometry(100,100,100, 20,20,20)而不是CubeGeometry(100,100,100,1,1,1)。)后一种方法可能会导致性能下降,所以我建议谨慎使用它。

I hope that others will contribute to this question with their solutions to this question. I struggled with it for quite a while myself before developing the solution described here.

我希望其他人能够通过解决这个问题的方式为这个问题做出贡献。在开发这里描述的解决方案之前,我在这方面已经挣扎了很长一段时间。

#2


6  

This really is far too broad of a topic to cover in a SO question, but for the sake of greasing the SEO of the site a bit, here's a couple of simple starting points:

在SO问题中,这个问题确实太过广泛,但为了润滑网站的搜索引擎优化,这里有几个简单的起点:

If you want really simple collision detection and not a full-on physics engine then check out Three.js: Simple Collision Detection

如果你想要真正简单的碰撞检测而不是全开物理引擎,那么请查看Three.js:简单碰撞检测

If, on the other hand you DO want some collision response, not just "did A and B bump?", take a look at Physijs, which is a super easy to use Ammo.js wrapper built around Three.js

另一方面,如果你想要一些碰撞响应,而不仅仅是“做A和B碰撞?”,请看一下Physijs,这是一个非常容易使用的Ammo.js包装器,围绕Three.js构建

#1


90  

In Three.js, the utilities CollisionUtils.js and Collisions.js no longer seem to be supported, and mrdoob (creator of three.js) himself recommends updating to the most recent version of three.js and use the Ray class for this purpose instead. What follows is one way to go about it.

在Three.js中,似乎不再支持实用程序CollisionUtils.js和Collisions.js,并且mrdoob(three.js的创建者)自己建议更新到最新版本的three.js并使用Ray类来实现此目的代替。以下是一种解决方法。

The idea is this: let's say that we want to check if a given mesh, called "Player", intersects any meshes contained in an array called "collidableMeshList". What we can do is create a set of rays which start at the coordinates of the Player mesh (Player.position), and extend towards each vertex in the geometry of the Player mesh. Each Ray has a method called "intersectObjects" which returns an array of objects that the Ray intersected with, and the distance to each of these objects (as measured from the origin of the Ray). If the distance to an intersection is less than the distance between the Player's position and the geometry's vertex, then the collision occurred on the interior of the player's mesh -- what we would probably call an "actual" collision.

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

I have posted a working example at:

我发布了一个工作示例:

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

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

You can move the red wireframe cube with the arrow keys and rotate it with W/A/S/D. When it intersects one of the blue cubes, the word "Hit" will appear at the top of the screen once for every intersection as described above. The important part of the code is below.

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

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...
    }
}

There are two potential problems with this particular approach.

这种特殊方法存在两个潜在的问题。

(1) When the origin of the ray is within a mesh M, no collision results between the ray and M will be returned.

(1)当光线的原点在网格M内时,将不返回光线和M之间的碰撞结果。

(2) It is possible for an object that is small (in relation to the Player mesh) to "slip" between the various rays and thus no collision will be registered. Two possible approaches to reduce the chances of this problem are to write code so that the small objects create the rays and do the collision detection effort from their perspective, or include more vertices on the mesh (e.g. using CubeGeometry(100, 100, 100, 20, 20, 20) rather than CubeGeometry(100, 100, 100, 1, 1, 1).) The latter approach will probably cause a performance hit, so I recommend using it sparingly.

(2)小的(相对于玩家网格)的物体可能在各种射线之间“滑动”,因此不会记录碰撞。减少此问题几率的两种可能方法是编写代码,以便小对象创建光线并从其视角执行碰撞检测工作,或在网格上包含更多顶点(例如,使用CubeGeometry(100,100,100, 20,20,20)而不是CubeGeometry(100,100,100,1,1,1)。)后一种方法可能会导致性能下降,所以我建议谨慎使用它。

I hope that others will contribute to this question with their solutions to this question. I struggled with it for quite a while myself before developing the solution described here.

我希望其他人能够通过解决这个问题的方式为这个问题做出贡献。在开发这里描述的解决方案之前,我在这方面已经挣扎了很长一段时间。

#2


6  

This really is far too broad of a topic to cover in a SO question, but for the sake of greasing the SEO of the site a bit, here's a couple of simple starting points:

在SO问题中,这个问题确实太过广泛,但为了润滑网站的搜索引擎优化,这里有几个简单的起点:

If you want really simple collision detection and not a full-on physics engine then check out Three.js: Simple Collision Detection

如果你想要真正简单的碰撞检测而不是全开物理引擎,那么请查看Three.js:简单碰撞检测

If, on the other hand you DO want some collision response, not just "did A and B bump?", take a look at Physijs, which is a super easy to use Ammo.js wrapper built around Three.js

另一方面,如果你想要一些碰撞响应,而不仅仅是“做A和B碰撞?”,请看一下Physijs,这是一个非常容易使用的Ammo.js包装器,围绕Three.js构建