Three.js - 用于碰撞检测的精确射线投射

Pro*_*r_D 4 javascript collision-detection three.js

我正在使用版本68的 Three.js .我正在使用相同的方法进行碰撞检测,因为这个人在这里使用,这在大多数时候都是很棒的(对你来说,这是一个很大的"谢谢"!):http://stemkoski.github.io/Three .js文件/冲突,Detection.html

如果您想从github下载它,这是源的链接.只需寻找Collision-Detection.html:https://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 ");
}
Run Code Online (Sandbox Code Playgroud)

这在大多数情况下都很有效,但有时我可以将立方体部分地移动到墙上,并且它不会记录碰撞.例如,看看这张图片:碰撞检测

它应该在左上角说"点击",那里只有一堆点,但事实并非如此. 注意:我也尝试了他的建议,并做了以下,但它似乎没有多大帮助:

THREE.BoxGeometry( 64, 64, 64, 8, 8, 8, wireMaterial ) // BoxGeometry is used in version 68 instead of CubeGeometry
Run Code Online (Sandbox Code Playgroud)

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

if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() )
Run Code Online (Sandbox Code Playgroud)

Ice*_*You 6

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

光线投射是一种很差的碰撞检测方法,因为它只检测光线投射的精确方向上的碰撞.它还有一些额外的边缘情况.例如,如果从另一个对象内部投射光线,则可能不会将另一个对象视为碰撞.作为另一个例子,Three.js中的光线投射使用边界球(或者,如果不可用,边界框)来计算光线交叉,因此光线可以与对象"相交",即使它们不会在视觉上击中它们.

如果你只处理球体或直立的长方体,那么检查碰撞是很简单的数学运算.(这就是为什么Three.js使用边界球和边界框 - 大多数需要进行碰撞检查的应用程序使用仅比渲染的几何更复杂的二次碰撞几何体.)如果它们的中心之间的距离小于球体,则球体会发生碰撞它们的半径之和.如果边缘重叠,则框会发生碰撞(例如,如果框1的左边缘位于框2的右边缘的左侧,并且框在垂直距离内,则它们的半高和水平距离的总和是他们的半长).

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

对于更复杂的应用程序,您可能希望使用Ammo.js,Cannon.js或Physi.js等库.

光线投射很吸引人的原因是因为它可以在不使用库的情况下使用更复杂的几何图形.然而,正如你所发现的那样,它并不完美.:-)

我写了一本名为Game Development with Three.js的书,它深入探讨了这个主题.(我不会在这里链接到它,因为我不是在这里推广它,但如果你感兴趣,可以谷歌吧.)这本书带有示例代码,显示如何进行基本的碰撞检测,包括完整的代码3D捕捉旗帜游戏.