【问题标题】:Three.js - Accurate ray casting for collision detectionThree.js - 用于碰撞检测的准确光线投射
【发布时间】:2014-10-31 01:59:36
【问题描述】:

我正在使用 Three.js,版本 68。我正在使用与此人在这里使用的相同方法进行碰撞检测,这在大多数情况下都很棒(非常感谢作者!):http://stemkoski.github.io/Three.js/Collision-Detection.html

如果你想从 github 下载它,这里是一个源链接。只需查找 Collision-Detection.htmlhttps://github.com/stemkoski/stemkoski.github.com

这是对碰撞检测很重要的代码:

var MovingCube;
var collidableMeshList = [];

var wall = new THREE.Mesh(wallGeometry, wallMaterial);
wall.position.set(100, 50, -100);
scene.add(wall);
collidableMeshList.push(wall);
var wall = new THREE.Mesh(wallGeometry, wireMaterial);
wall.position.set(100, 50, -100);
scene.add(wall);

var wall2 = new THREE.Mesh(wallGeometry, wallMaterial);
wall2.position.set(-150, 50, 0);
wall2.rotation.y = 3.14159 / 2;
scene.add(wall2);
collidableMeshList.push(wall2);
var wall2 = new THREE.Mesh(wallGeometry, wireMaterial);
wall2.position.set(-150, 50, 0);
wall2.rotation.y = 3.14159 / 2;
scene.add(wall2);

var cubeGeometry = new THREE.CubeGeometry(50,50,50,1,1,1);
var wireMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe:true } );
MovingCube = new THREE.Mesh( cubeGeometry, wireMaterial );
MovingCube.position.set(0, 25.1, 0);


// collision detection:
//   determines if any of the rays from the cube's origin to each vertex
//      intersects any face of a mesh in the array of target meshes
//   for increased collision accuracy, add more vertices to the cube;
//      for example, new THREE.CubeGeometry( 64, 64, 64, 8, 8, 8, wireMaterial )
//   HOWEVER: when the origin of the ray is within the target mesh, collisions do not occur
var originPoint = MovingCube.position.clone();

for (var vertexIndex = 0; vertexIndex < MovingCube.geometry.vertices.length; vertexIndex++)
{       
    var localVertex = MovingCube.geometry.vertices[vertexIndex].clone();
    var globalVertex = localVertex.applyMatrix4( MovingCube.matrix );
    var directionVector = globalVertex.sub( MovingCube.position );

    var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
    var collisionResults = ray.intersectObjects( collidableMeshList );
    if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() ) 
        appendText(" Hit ");
}

这在大多数情况下都很好用,但有时我可以将立方体部分移动到墙上,并且不会发生碰撞。比如看这张图:

它应该在只有一堆点的左上角显示“Hit”,但事实并非如此。 注意:我也尝试了他的建议并做了以下操作,但似乎没有多大帮助:

THREE.BoxGeometry( 64, 64, 64, 8, 8, 8, wireMaterial ) // BoxGeometry is used in version 68 instead of CubeGeometry

有人知道这种方法如何更准确吗? 另一个问题:有谁知道下面的if语句是干什么用的,即为什么物体的距离必须小于方向向量的长度?:

if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() )

【问题讨论】:

    标签: javascript three.js collision-detection


    【解决方案1】:

    首先回答您的最后一个问题:该行检测碰撞是否发生在您的 MovingCube 内部。您的光线投射代码从 MovingCube 的位置向其每个顶点投射光线。返回与射线相交的任何内容,以及与找到相交对象的 MovingCube 位置的距离 (collisionResults[0].distance)。将该距离与从 MovingCube 的位置到相关顶点的距离进行比较。如果到碰撞的距离小于到顶点的距离,则碰撞发生在立方体内部。

    光线投射是一种糟糕的碰撞检测方法,因为它只能检测光线投射方向上的碰撞。它还有一些额外的边缘情况。例如,如果光线从另一个对象内部投射,则可能不会认为另一个对象正在发生碰撞。再举一个例子,Three.js 中的光线投射使用边界球体(或者,如果不可用,则使用边界框)来计算光线相交,因此光线可以与物体“相交”,即使它们不会在视觉上击中它们。

    如果您只处理球体或直立长方体,则检查碰撞是一种简单的数学运算。 (这就是 Three.js 使用边界球体和边界框的原因——大多数需要进行碰撞检查的应用程序使用次要仅碰撞几何体,这些几何体没有渲染的几何体复杂。)如果球体中心之间的距离小于它们的半径之和。如果边缘重叠,盒子就会发生碰撞(例如,如果盒子 1 的左边缘在盒子 2 的右边缘的左边,并且盒子在垂直距离之内,它们的半高之和和水平距离之和它们的半长)。

    对于某些应用程序,您还可以使用体素,例如将世界划分为立方体单位,进行方框数学运算,然后说如果两个对象与同一个立方体单位重叠,它们就会发生碰撞。

    对于更复杂的应用程序,您可能需要使用像 Ammo.js、Cannon.js 或 Physi.js 这样的库。

    光线投射之所以吸引人,是因为它可以在不使用库的情况下处理更复杂的几何图形。然而,正如您所发现的,它并不完美。 :-)

    我写了一本名为“使用 Three.js 进行游戏开发”的书,其中深入探讨了这个主题。 (我不会在这里链接到它,因为我不是在这里推广它,但如果你有兴趣,可以谷歌它。)这本书附带了示例代码,展示了如何进行基本的碰撞检测,包括完整的代码3D 夺旗游戏。

    【讨论】:

    • 感谢您的精彩回答!我正在尝试使用three.js 让边界框工作。基本上你可以做以下事情:object.geometry.computeBoundingBox(); //object is THREE.Meshvar objectBoundingBox = object.geometry.boundingBox.clone(); 然后你可以在另一个网格上做同样的事情,然后做以下事情来看看它们是否相交:if (object.isIntersectionBox(otherObjectBoundingBox)) 但是,这对我来说总是正确的! Box3 是边界框,来源在这里:link 知道我做错了什么吗?
    • 在我之前的评论 if 语句中犯了一个错误。应该是这样的:if (objectBoundingBox.isIntersectionBox(otherObjectBoundingBox))
    • 我只是 console.log() 你正在比较的盒子,并手动尝试来自 isIntersectionBox 源的条件,看看你得到什么结果并从那里去
    • 这是该边界框示例的 jsfiddle:jsfiddle。如您所见,立方体彼此相距甚远,但 isIntersectionBox 返回 true。似乎边界框正在正确计算。我不确定我能做些什么来让它永远是假的。
    • 好吧,看起来这篇文章有效!:Three.js: wrong BoundingBox after scaling a geometry。感谢使用边界框的想法 =)
    猜你喜欢
    • 2012-11-07
    • 2023-04-04
    • 2015-11-11
    • 2019-11-18
    • 1970-01-01
    • 2016-06-19
    • 2012-10-01
    • 1970-01-01
    • 2014-06-29
    相关资源
    最近更新 更多