6

I'm working on a 3d virtual home project. everythings works fine except collision detection. I use PointerLockControls for my camera and movement. but i'm not sure how to detec collision in every possible directions. For simplicity i started with just forward and backward collision to a simple cube on (0,0,0):

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

Then:

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);
    }
}

But when i get close enough to my cube, console shows me both rays hit the cube! so why? Is there any problem with my rays? vector(0,0,1) should be backward and (0,0,-1) should be forward, right? Please help me, before i get lost in 3d! Thanks.

Mehdi Seifi
  • 515
  • 11
  • 22
  • Try it with just one ray and see if you can figure it out from there. I think each ray is getting cast in the opposite direction you think it is, so (depending on which way you're facing) the "forward" one actually starts at the intersection with your cube and goes towards the camera, while the "backward" one starts behind the camera and goes towards it. So try switching the order of the subtraction that derives your raycaster direction. – IceCreamYou Sep 01 '13 at 08:37
  • After some more testing, i find out there is a relation between four normal vectors ((0,0,1), (0,0,-1), (1,0,0), (-1,0,0)) and camera(pointerlock controls) **direction**. For example when i rotate the camera 180 degrees, now the forward vector should be the backward vector and so on. right? So what is the formula to calculate the actual direction vector for raycasting? – Mehdi Seifi Sep 01 '13 at 20:14
  • Examples: http://threejs.org/examples/misc_controls_pointerlock.html http://stemkoski.github.io/Three.js/Collision-Detection.html And more generally if you want to get the camera's direction: http://stackoverflow.com/questions/14023764/how-to-get-orientation-of-camera-in-three-js/14024779#14024779 – IceCreamYou Sep 01 '13 at 21:41
  • PointerLockerControls already has a **getDirection** method and ray casting with that give you intersections with object in front of camera. But what i'm looking for is the intersection with objects behind or besides of camera when you move camera backward or to the left/right side. – Mehdi Seifi Sep 02 '13 at 07:48
  • I understand that. The examples I gave cast rays in various directions around the player. Also if you have the camera's direction you can use that to derive other directions. – IceCreamYou Sep 02 '13 at 15:44

1 Answers1

10

Finally i discovered!! the solution. i'm not good at math, but at the end i figure it out.
After i get direction from pointer-locker controls, depend on which key is pressed, i put the direction into a rotation matrix to get the actual direction vector(thanks for the clue 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);
}
}

Also i made some changes to the PointerLockControls.js to stop moving when camera hit the collider object. I upload my sample here: CameraRayCasting.zip

Update
Finally i've found some time to finish my TouchControls project. It uses threejs v0.77.1 and supports touch and hit-testing.
check it out here: TouchControls

Mehdi Seifi
  • 515
  • 11
  • 22
  • Would give this answer a +10!!! Using three.js r71. Althrough I used to hit detection instead of collision. We most definitely need more help to use webgl/three.js. – Paulo Bueno Apr 09 '15 at 11:59