Three.js,指针锁定和碰撞检测

6

我正在进行一个虚拟家庭三维项目。除了碰撞检测之外,一切都运作良好。我使用PointerLockControl来控制我的相机和移动,但是我不确定如何在每个可能的方向上检测碰撞。为简单起见,我从前后方向的碰撞开始,对位于(0,0,0)上的一个简单立方体进行碰撞检测:

rays = [
    new THREE.Vector3(0, 0, 1),
    new THREE.Vector3(0, 0, -1)
];

然后:

function detectCollision() {
var vector;
var projector = new THREE.Projector();

for (var i = 0; i < rays.length; i++) {
    var vector = rays[i].clone();
    projector.unprojectVector(vector, camera);

    var rayCaster = new THREE.Raycaster(controls.getObject().position, vector.sub(controls.getObject().position).normalize());
    var intersects = rayCaster.intersectObject(cube, true);

    if (intersects.length > 0 && intersects[0].distance < 50) {
        console.log(vector);
        console.log(i, intersects);
        $("#status").text("Collision detected @ " + rays[i].x + "," + rays[i].z +
            "<br \>" + intersects[0].distance);
    }
}

但是当我靠近我的立方体时,控制台显示两条射线都击中了立方体!那么为什么呢?我的射线有问题吗?向量(0,0,1)应该是向后的,而(0,0,-1)应该是向前的,对吗?请在我迷失在3D之前帮助我!谢谢。


尝试只使用一条光线,看看你能否从那里弄清楚。我认为每个光线都是以你认为的相反方向投射的,因此(取决于你面对的方向),“前进”光线实际上从与你的立方体相交处开始,朝着相机前进,而“后退”光线则从相机后面开始,朝着相机前进。因此,请尝试切换导出射线投射器方向的减法顺序。 - IceCreamYou
经过更多测试,我发现四个法向量((0,0,1),(0,0,-1),(1,0,0),(-1,0,0))与相机(pointerlock控件)方向之间存在关系。例如,当我将相机旋转180度时,现在前向量应该是后向量,依此类推。那么,计算用于射线投射的实际方向向量的公式是什么? - Mehdi Seifi
示例:http://threejs.org/examples/misc_controls_pointerlock.html http://stemkoski.github.io/Three.js/Collision-Detection.html 更一般地,如果您想获取相机的方向:https://dev59.com/5mzXa4cB1Zd3GeqPT3dk#14024779 - IceCreamYou
PointerLockerControls已经有一个getDirection方法,使用它进行光线投射可以得到相机前方物体的交点。但我想要的是当相机向后移动或向左/右侧移动时,与相机后面或旁边的物体的交点。 - Mehdi Seifi
我理解了。我所举的例子是在玩家周围以不同方向投射光线。此外,如果你有相机的方向,你可以用它来推导出其他方向。 - IceCreamYou
1个回答

10

最终我找到了解决方案!!虽然我不擅长数学,但最终我还是想通了。
在接收到指针锁定控制的指示后,根据按下的键,我将方向放入旋转矩阵中以获取实际的方向向量(感谢Icemonster给出的线索):

function detectCollision() {
unlockAllDirection();

var rotationMatrix;
var cameraDirection = controls.getDirection(new THREE.Vector3(0, 0, 0)).clone();

if (controls.moveForward()) {
    // Nothing to do!
}
else if (controls.moveBackward()) {
    rotationMatrix = new THREE.Matrix4();
    rotationMatrix.makeRotationY(180 * Math.PI / 180);
}
else if (controls.moveLeft()) {
    rotationMatrix = new THREE.Matrix4();
    rotationMatrix.makeRotationY(90 * Math.PI / 180);
}
else if (controls.moveRight()) {
    rotationMatrix = new THREE.Matrix4();
    rotationMatrix.makeRotationY((360-90) * Math.PI / 180);
}
else return;

if (rotationMatrix !== undefined){
    cameraDirection.applyMatrix4(rotationMatrix);
}
var rayCaster = new THREE.Raycaster(controls.getObject().position, cameraDirection);    
var intersects = rayCaster.intersectObject(hitMesh, true);  

$("#status").html("camera direction x: " + cameraDirection.x + " , z: " + cameraDirection.z);

if ((intersects.length > 0 && intersects[0].distance < 25)) {
    lockDirection();
    $("#status").append("<br />Collision detected @ " + intersects[0].distance);

    var geometry = new THREE.Geometry();
    geometry.vertices.push(intersects[0].point);
    geometry.vertices.push(controls.getObject().position);
    scene.remove(rayLine);
    rayLine = new THREE.Line(geometry, new THREE.LineBasicMaterial({color: 0xFF00FF, linewidth: 2}));
    scene.add(rayLine);
}
}

我还对PointerLockControls.js做了一些更改,以防止相机碰到碰撞器对象时移动。 我上传了我的示例,此处可下载:CameraRayCasting.zip

更新
最终我有时间完成了我的TouchControls项目。它使用了threejs v0.77.1,并支持触摸和命中测试。
在这里查看:TouchControls


会给这个答案一个+10!!! 使用的是three.js r71。虽然我使用了命中检测而不是碰撞检测。我们绝对需要更多的帮助来使用webgl/three.js。 - Paulo Bueno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接