Thursday, July 26, 2012

Collision Detection in Three.js

‹prev | My Chain | next›

I was not quite able to get collision detection working in Three.js last night. I don't really need it for my immediate need, which is keeping my avatar on its tropical island:


I can already achieve the necessary boundary limits with simple position checks. Instead, I would like to use collision detection to do this. So I create a wall:
  var wallGeometry = new THREE.CubeGeometry(100, 1000, 5000, 5, 5, 5)
    , wallMaterial = new THREE.MeshBasicMaterial({color: 0xFFD700})
    , wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
//  wallMesh.position.x = -M*0.6;
  scene.add(wallMesh);
And try to detect a collision with this wall on every render():
function render() {
  // ...
  detectCollision();
  // ...
}
Collision detection is a three step process in Three.js. First, I need to know where I am and in which direction I am facing. That is, I need a Ray. Second I need to know if that Ray crosses another object (the wall in this case). Lastly, I need to know the distance from the object. Last night, with the help of a Three.js "bug report", I cobbled together a collision detection algorithm of:
function detectCollision() {
  var vector = controls.target.clone().subSelf( controls.object.position ).normalize();
  var ray = new THREE.Ray(controls.position, vector);
  var intersects = ray.intersectObjects(walls);

  if (intersects.length > 0) console.log(intersects);
}
This failed to work, even when the player was standing in the middle of the wall:


After debugging this some, I realize that my problem is that my Ray has a null position. Earlier in the function, I got the position of my avatar from controls.object.position. For the Ray, I am just trying controls.position, which is undefined. Such is the price of copying code without really understanding it.

In the end, I also have to add a distance check:
function detectCollision() {
  var vector = controls.target.clone().subSelf( controls.object.position ).normalize();
  var ray = new THREE.Ray(controls.object.position, vector);
  var intersects = ray.intersectObjects(walls);

  if (intersects.length > 0) {
    if (intersects[0].distance < 5) {
      console.log(intersects);
    }
  }
}
But, with that, I have my wall collision detection working. I call it a night here. Up tomorrow, I will rework this into a useful island boundary, which should conclude my Three.js work.


Day #459

No comments:

Post a Comment