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

新手上路,请多包涵

我正在使用 three.js。

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

如果这些几何图形相交(或者如果翻译 _会相交_),我想将其检测为碰撞。

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

原文由 eqiproo 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 640
2 个回答

在 Three.js 中,实用程序 CollisionUtils.js 和 Collisions.js 似乎不再受支持,mrdoob(three.js 的创建者)本人建议更新到最新版本的 three.js 并为此使用 Ray 类反而。下面是一种解决方法。

这个想法是这样的:假设我们要检查一个名为“Player”的给定网格是否与名为“collidableMeshList”的数组中包含的任何网格相交。我们可以做的是创建一组光线,这些光线从 Player 网格 (Player.position) 的坐标开始,并延伸到 Player 网格几何体中的每个顶点。每条 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) 对于较小的对象(相对于 Player 网格而言)可能会在各种光线之间“滑动”,因此不会记录碰撞。减少出现此问题的可能性的两种可能方法是编写代码,以便小对象创建光线并从它们的角度进行碰撞检测,或者在网格上包含更多顶点(例如使用 CubeGeometry(100, 100, 100, 20, 20, 20) 而不是 CubeGeometry(100, 100, 100, 1, 1, 1).) 后一种方法可能会导致性能下降,因此我建议谨慎使用它。

我希望其他人将通过他们对这个问题的解决方案为这个问题做出贡献。在开发此处描述的解决方案之前,我自己也为此苦苦挣扎了一段时间。

原文由 Stemkoski 发布,翻译遵循 CC BY-SA 3.0 许可协议

Lee 答案的更新版本,适用于最新版本的 three.js

 for (var vertexIndex = 0; vertexIndex < Player.geometry.attributes.position.array.length; vertexIndex++)
{
    var localVertex = new THREE.Vector3().fromBufferAttribute(Player.geometry.attributes.position, vertexIndex).clone();
    var globalVertex = localVertex.applyMatrix4(Player.matrix);
    var directionVector = globalVertex.sub( Player.position );

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

原文由 Kartheyan 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题