Three.js: Simple Collision Detection

I’ve been spending some time trying to work out how to perform basic collision detection with the three.js library. After a combination of Googling, looking at the three.js source code and looking at the sample code on the three.js github pages I’ve managed to get something working.

I found the best collision detection example at Mr.Doob’s three.js repository on github. In fact that are a number of examples there. These examples use a couple of utility files, namely CollisionUtils.js and Collisions.js that can be found along with the example code. I’m pretty sure that I checked out the latest revision of the three.js code from github but the CollisionUtils.js and Collisions.js utility files that are available here didn’t seem to come with it. I used these utility files in order to implement collision detection in my little exploration where they allowed me to use:

THREE.Collisions.colliders.push(
	THREE.CollisionUtils.MeshOBB( cube ) );

Essentially this creates an Object Bounding Box (OBB) around a THREE.Mesh object (cube in this example) and adds it to a collision detection list (THREE.Collisions.colliders as defined in Collisions.js). The MeshOBB() method is defined in the CollisionUtils.js file. In my code I added a number of cuboid objects to my 3D scene and also added them to the collision detection list (using the code snippet above). My plan was to then determine if my moving 3D object, or character, had collided with any of these cuboids.

In order to determine if my moving character had collided with any of the other objects in the scene (the objects on the collision detection list) I used the THREE.Ray class. The following segment of code determines the position of a theoretical focal point of this ray (think beam of light) that lies somewhere in front of our character. As our character rotates the focal point rotates also.

I believe that the distance specified in the second argument to the THREE.Ray constructor essentially represents the direction in which the ray is to be sent. I’ve used a value of 1000 in this example but it could have been a much smaller value.

// Using a little trigonometry calculate a point in
// space 1000 units in front of our character
var deltaX = Math.floor(Math.sin(mesh.rotation.y) * 1000);
var deltaZ = Math.floor(Math.cos(mesh.rotation.y) * 1000);

// Calculate where this collision focus point is in
// relation to our character position
var focusX = mesh.position.x - deltaX;
var focusZ = mesh.position.z - deltaZ;

// Fire a ray from the centre point of our character to the
// collision focus point
var ray = new THREE.Ray(mesh.position,
	new THREE.Vector3(focusX, 0, focusZ));

var c = THREE.Collisions.rayCastNearest( ray );

if(c && c.distance <= 50)
{
	console.log(c.distance);
	tween.stop();
}

The rayCastNearest() method is used to determine if the ray coincides with any of the objects that were added to the collision detection list that was populated earlier. If there is an object (or collider object as I’ve shown in the figure below) that the ray intersects then the object returned by the rayCastNearest() method includes a distanceproperty that tells us the distance between position of our character and the collider object. In the code extract above I’ve specified a distance of <= 50 as my character had a length of 100 and so 50 is the point at which the face of my character would potentially collide with any collider objects. If a collision occurs I stop the tweening update so that my character stops moving.

Collision detection

Note: In the figure above I’m pretty sure that I should have shown the z-axis as -z.

Once I’ve actually produced a practical demonstration of this theory I will post again with an example.

Finally

I just wanted to provide some further links as I did a little bit of trawling on the net when I was first researching into collision detection. I’m not sure that I’m using the best technique but there still seems to be validity in the methods that I’ve used. I came across a discussion on the Mr.Doob github pages where someone was unsure of how to find the direction for the THREE.Ray. The individual concerned did some searching themselves and came up with a slightly different method of determining the Ray direction than I did.

At one stage I was considering the use of the JigLibJS library as discussed on Tim Poon’s site. Didn’t go down this road in the end but could be interesting.

Of course I also found the code examples that come with the three.js library fairly useful too.

18 Responses to Three.js: Simple Collision Detection

  1. Nathalia says:

    The code isn’t working in my machine. I create the cube but when I put: THREE.Collisions.colliders.push( THREE.CollisionUtils.MeshOBB( cube ) );

    Simply nothing appear in the canvas. Does anyone have idea what’s happening? I’m using the last version of Three.js.

    Thanks

    • gblake says:

      Don’t forget that the THREE.Collisions.push method simply places an object in the THREE.Collisions array, it doesn’t place it in the scene. You still need the call to scene.add(cube) for example to add the cube object to the scene.

      I’m wishing that I’d put a more complete code example on the site now!

      • Nathalia says:

        I don’t forget to add the cube in the scene… My code is:

        function createCube( s, p ) {

        cube = new THREE.Mesh (
        new THREE.CubeGeometry( s, s, s ),
        new THREE.MeshLambertMaterial( { color: 0xFF0000 } )
        );

        cube.position = p;
        scene.add( cube );

        THREE.Collisions.colliders.push( THREE.CollisionUtils.MeshOBB( cube ) );

        };

        Is it something here? When I comment the last line the cube appears, otherwise nothing appears.

        Thanks

        • gblake says:

          Nathalia

          Have you got the Collisions.js and CollisionUtils.js files from the github repository? Go here and you’ll find the files that you need.

          You may find that, if you leave the THREE.Collisions.colliders.push() function call in your code and debug with Firebug or Chrome that you get an error on this line if the .js files are missing.

          Hope this helps.

          Graham

          • Nathalia says:

            It’s strange… I copy both Collisions.js and CollisionUtils.js from github and called then in the html code. And in firefox appears the follow error:

            b.x is undefined
            var min = new THREE.Vector3( b.x[0], b.y[0], b.z[0] );

            CollisionUtils.js (line 14)

            The error is inside the CollisionUtils code 0_o

  2. gblake says:

    I notice in the MeshOBB constructor (above line 14 of CollisionUtils.js) there are the following lines of code:

    m.geometry.computeBoundingBox();
    var b = m.geometry.boundingBox;

    If you place a breakpoint at the first of these lines, I’m wondering if the computeBoundingBox() method sets the boundingBox property correctly.

    Sorry Nathalia, it worked for me!!

    • gblake says:

      I’ve just debugged this a little more. I edited my local copy of the CollisionUtils.js file and modified the MeshOBB constructor like this:

      //var min = new THREE.Vector3( b.x[0], b.y[0], b.z[0] );
      //var max = new THREE.Vector3( b.x[1], b.y[1], b.z[1] );
      var min = b.min;
      var max = b.max;

      It seems that min and max are now properties of the m.geometry.boundingBox object, i.e. of b.

      Once I’d one this my local working copy also worked. I had to ensure that I had my local web server running and that I accessed it via http://localhost but it worked ok.

      I guess that there have been some changes to the three.js library since that version of the CollisionUtils.js file was created. This is one of the problems that I am finding with three.js in that it is still evolving.

      Let me know if it works.

      Happy coding!
      Graham

  3. Nathalia says:

    Graham, have you ever tried THREE.FirstPersonControls? My idea is to build an environment with walls and the person can not overcome them. Any suggestion or help?

    Thanks a lot

  4. gar says:

    I’ve been using CollisionUtils.js with r48 which worked fine. It seems to break using r49. This is the error I’m getting:

    Uncaught TypeError: Cannot read property ‘x’ of undefined Three.js:14
    THREE.Vector3.sub Three.js:14
    THREE.CollisionSystem.rayTriangle Three.js:1009
    THREE.CollisionSystem.rayMesh Three.js:970
    THREE.CollisionSystem.rayCastNearest Three.js:904