我正在使用Three.js,版本 68 。我使用相同的方法进行碰撞检测,因为这个人在这里使用,这在大多数情况下是很好的(一个大的#34;谢谢你"去找作者!):{{3} }
如果要从github下载,请输入以下链接。只需查看 Collision-Detection.html :http://stemkoski.github.io/Three.js/Collision-Detection.html
即可以下是对碰撞检测很重要的代码:
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 ");
}
这在大多数情况下效果很好,但有时我可以将立方体部分移动到墙上,并且它不会记录碰撞。例如,请查看此图片:
它应该说&#34; Hit&#34;在左上角,只有一堆点,而不是。 注意:我也尝试了他的建议并做了以下事情,但它似乎没有多大帮助:
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() )
答案 0 :(得分:6)
首先回答您的上一个问题:该行检测您的MovingCube内是否发生了碰撞。您的光线投射代码会将MovingCube位置的光线投射到每个顶点。返回与光线相交的任何内容,以及与找到相交对象的MovingCube位置的距离(collisionResults[0].distance
)。将该距离与从MovingCube的位置到相关顶点的距离进行比较。如果到碰撞的距离小于到顶点的距离,则碰撞发生在立方体内。
光线投射是一种很差的碰撞检测方法,因为它只检测投射光线的精确方向上的碰撞。它还有一些额外的边缘情况。例如,如果从另一个对象内部投射光线,则可能不会将另一个对象视为碰撞。作为另一个例子,Three.js中的光线投射使用边界球(或者,如果不可用的话,边界框)来计算光线交叉,因此光线可以相交&#34;对象,即使他们不会在视觉上击中它们。
如果您只处理球体或直立长方体,那么检查碰撞的直接数学算法就是如此。 (这就是为什么Three.js使用边界球和边界框的原因 - 大多数需要进行碰撞检查的应用程序使用的二次仅碰撞几何图形比复制的几何图形复杂得多。)如果它们之间的距离较小,则球体会发生碰撞中心小于它们的半径之和。如果边缘重叠,则框会发生碰撞(例如,如果框1的左边缘位于框2的右边缘的左侧,并且框在垂直距离内,则它们的半高和水平距离的总和是他们的半长。)
对于某些应用程序,您也可以使用体素,例如:将世界划分为立方单位,进行框数学,并说如果两个对象与同一个立方体单元重叠,则会发生碰撞。
对于更复杂的应用程序,您可能希望使用Ammo.js,Cannon.js或Physi.js等库。
光线投射很吸引人的原因是因为它可以在不使用库的情况下使用更复杂的几何图形。然而,正如您所发现的那样,它并不完美。 : - )
我写了一本名为Game Development with Three.js的书,深入探讨了这个话题。 (我在这里没有链接到它,因为我不是来推广它,但是如果你感兴趣的话,你可以谷歌吧。)这本书带有示例代码,展示如何进行基本的碰撞检测,包括3D捕捉旗帜游戏的完整代码。