如何阻止相机穿过墙壁?

时间:2010-07-17 15:05:38

标签: 3d

我正在使用JigLibGLGE制作游戏。摄像机按照我想要的方式跟随播放器,但是当播放器靠近墙壁时,摄像机移动到墙壁的另一侧,这在需要快速反应的情况下很烦人。

我尝试使用拾取器移动相机,当它看不到播放器时,但它只移动到墙的一半在它前面而一半在它后面,制作一个恼人的分屏效果,其中一半屏幕是空白的。

camera.setLocY(Math.max(playerMesh.getLocY() - 10, 3));
camera.setRotY(playerHeading);
camera.setLocX(playerMesh.getLocX() + Math.sin(playerHeading) * Math.max(camera.getLocY() - playerMesh.getLocY() + 5, 0));
camera.setLocZ(playerMesh.getLocZ() + Math.cos(playerHeading) * Math.max(camera.getLocY() - playerMesh.getLocY() + 5, 0));
camera.setRotX(Math.atan2(playerMesh.getLocY() - camera.getLocY(), Math.max(camera.getLocY() - playerMesh.getLocY() + 5, 0)));

var playerVec = [playerMesh.getLocX(), playerMesh.getLocY(), playerMesh.getLocZ()],
    cameraVec = [camera.getLocX(), camera.getLocY(), camera.getLocZ()];
scene.removeChild(playerMesh);
scene.removeChild(floor);
do {
    var ray = scene.pick(canvas.width / 2, canvas.height / 2);
    if (ray.distance && ray.distance < GLGE.distanceVec3(playerVec, cameraVec)) {
        camera.setLocX(ray.coord[0]);
        camera.setLocY(ray.coord[1]);
        camera.setLocZ(ray.coord[2]);
        cameraVec = ray.coord;
        camera.setRotX(Math.atan2(playerMesh.getLocY() - camera.getLocY(), Math.max(camera.getLocY() - playerMesh.getLocY(), 0)));
    }
} while (ray.distance && ray.distance < GLGE.distanceVec3(playerVec, cameraVec));
scene.addChild(playerMesh);
scene.addChild(floor);

是否有资源我可以找到有关如何移动相机以避免墙壁的信息?我的代码错了吗?

3 个答案:

答案 0 :(得分:3)

您只是在测试中使用相机位置。

您需要考虑相机的视野。最简单的是你需要检查视锥的极端点以及实际位置的更多点。

另一种技术是制作相机球体或锥体并用它进行碰撞检测。显然,对于大多数情况来说,这样做太贵了,所以只有当相机距离墙壁一定距离时才这样做。

答案 1 :(得分:0)

您不仅需要防止相机撞到墙壁,而且在决定相机应该离墙壁有多远时必须考虑剪裁距离。

当相机占据墙壁时,剪裁导致墙壁被夹在相机FOV内部,结果就是你会看到墙壁,以及它背后的东西。在“古墓丽影2”中可以清楚地看到这个错误(在几个地方你可以让相机“看到”墙的剪裁,因此你会看到墙后面的任何东西大约有3或4个像素)

游戏Sauerbraten(或Cube 2)因处理相机而闻名,它是开源的(所以你可以偷看并知道它们是如何制作的)

答案 2 :(得分:0)

我找到了一个更简单的解决方案 - 我放置了几个摄像头并制作了一些代码来自动切换到最接近播放器的代码。

function selectCamera(point) {
    var pointVec3 = convertToVec3(point);
    cameras.sort(function(a, b){
        return GLGE.distanceVec3(pointVec3, convertToVec3(a.getPosition())) - GLGE.distanceVec3(pointVec3, convertToVec3(b.getPosition()));
    });
    scene.setCamera(cameras[0]);

    // Now, point it in the right direction!
    var pos = scene.camera.getPosition(),
        coord = [pos.x-point.x, pos.y-point.y, pos.z-point.z];
    scene.camera.setRotOrder(GLGE.ROT_YZX);
    scene.camera.setRotX(Math.atan2(Math.sqrt(coord[2] * coord[2] + coord[0] * coord[0]), coord[1]) - Math.PI / 2);
    scene.camera.setRotY(Math.atan2(coord[0], coord[2]));
}