Over 80 practical recipes for creating stunning graphics and effects with the fascinating Away3D engine
In this article, you are going to learn how to check intersection (collision) between 3D objects.
This recipe will teach you the fundamentals of collision detection between objects in 3D space. We are going to learn how to perform a few types of intersection tests. These tests can hardly be called collision detection in their physical meaning, as we are not going to deal here with any simulation of collision reaction between two bodies. Instead, the goal of the recipe is to understand the collision tests from a mathematical point of view. Once you are familiar with intersection test techniques,the road to creating of physical collision simulations is much shorter. There are many types of intersection tests in mathematics. These include some simple tests such as AABB (axially aligned bounding box), Sphere - Sphere, or more complex such as Triangle - Triangle, Ray - Plane, Line - Plane, and more. Here, we will cover only those which we can achieve using built-in Away3D functionality. These are AABB and AABS (axially aligned bounding sphere) intersections, as well as Ray-AABS and the more complex Ray- Triangle. The rest of the methods are outside of the scope of this article and you can learn about applying them from various 3D math resources.
Setup an Away3D scene in a new file extending AwayTemplate. Give the class a name CollisionDemo.
In the following example, we perform an intersection test between two spheres based on their bounding boxes volumes. You can move one of the spheres along X and Y with arrow keys onto the second sphere. On the objects overlapping, the intersected (static) sphere glows with a red color.
CollisionDemo.as
package
{
public class CollisionDemo extends AwayTemplate
{
private var _objA:Sphere;
private var _objB:Sphere;
private var _matA:ColorMaterial;
private var _matB:ColorMaterial;
private var _gFilter_GlowFilter=new GlowFilter();
public function CollisionDemo()
{
super();
_cam.z=-500;
}
override protected function initMaterials() : void{
_matA=new ColorMaterial(0xFF1255);
_matB=new ColorMaterial(0x00FF11);
}
override protected function initGeometry() : void{
_objA=new Sphere({radius:30,material:_matA});
_objB=new Sphere({radius:30,material:_matB});
_view.scene.addChild(_objA);
_view.scene.addChild(_objB);
_objB.ownCanvas=true;
_objA.debugbb=true;
_objB.debugbb=true;
_objA.transform.position=new Vector3D(-80,0,400);
_objB.transform.position=new Vector3D(80,0,400);
}
override protected function initListeners() : void{
super.initListeners();
stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown);
}
override protected function onEnterFrame(e:Event) : void{
super.onEnterFrame(e);
if(AABBTest()){
_objB.filters=[_gFilter];
}else{
_objB.filters=[];
}
}
private function AABBTest():Boolean{
if(_objA.parentMinX>_objB.parentMaxX||_objB.parentMinX>_objA.
parentMaxX){
return false;
}
if(_objA.parentMinY>_objB.parentMaxY||_objB.parentMinY>_objA.
parentMaxY){
return false;
}
if(_objA.parentMinZ>_objB.parentMaxZ||_objB.parentMinZ>_objA.
parentMaxZ){
return false;
}
return true;
}
private function onKeyDown(e:KeyboardEvent):void{
switch(e.keyCode){
case 38:_objA.moveUp(5); break;
case 40:_objA.moveDown(5); break;
case 37:_objA.moveLeft(5); break;
case 39:_objA.moveRight(5); break;
case 65:_objA.rotationZ-=3; break;
case 83:_objA.rotationZ+=3; break;
default:
}
}
}
}
In this screenshot, the green sphere bounding box has a red glow while it is being intersected by the red sphere's bounding box:
Testing intersections between two AABBs is really simple. First, we need to acquire the boundaries of the object for each axis. The box boundaries for each axis of any Object3D are defined by a minimum value for that axis and maximum value. So let's look at the AABBTest() method. Axis boundaries are defined by parentMin and parentMax for each axis, which are accessible for each object extending Object3D.
You can see that Object3D also has minX,minY,minZ and maxX,maxY,maxZ. These properties define the bounding box boundaries too, but in objects space and therefore aren't helpful in AABB tests between two objects.
So in order for a given bounding box to intersect a bounding box of other objects, three conditions have to be met for each of them:
If one of the conditions is not met for any of the two AABBs, there is no intersection. The preceding algorithm is expressed in the AABBTest() function:
private function AABBTest():Boolean{
if(_objA.parentMinX>_objB.parentMaxX||_objB.parentMinX>_objA.
parentMaxX){
return false;
}
if(_objA.parentMinY>_objB.parentMaxY||_objB.parentMinY>_objA.
parentMaxY){
return false;
}
if(_objA.parentMinZ>_objB.parentMaxZ||_objB.parentMinZ>_objA.
parentMaxZ){
return false;
}
return true;
}
As you can see, if all of the conditions we listed previously are met, the execution will skip all the return false blocks and the function will return true, which means the intersection has occurred.
Now let's take a look at the rest of the methods for collision detection, which are AABS-AABS, Ray-AABS, and Ray-Triangle.
The intersection test between two bounding spheres is even simpler to perform than AABBs. The algorithm works as follows.
If the distance between the centers of two spheres is less than the sum of their radius, then the objects intersect. Piece of cake! Isn't it? Let's implement it within the code.
The AABS collision algorithm gives us the best performance. While there are many other even more sophisticated approaches, try to use this test if you are not after extreme precision. (Most of the casual games can live with this approximation).
First, let's switch the debugging mode of _objA and _objB to bounding spheres. In the last application we built, go to the initGeometry() function and change:
_objA.debugbb=true;
_objB.debugbb=true;
To:
_objA.debugbs=true;
_objB.debugbs=true;
Next, we add the function to the class which implements the algorithm we described previously:
private function AABSTest():Boolean{
var dist_Number=Vector3D.distance(_objA.position,_objB.
position);
if(dist<=(_objA.radius+_objB.radius)){
return true;
}
return false;
}
Finally, we add the call to the method inside onEnterFrame():
if(AABSTest()){
_objB.filters=[_gFilter];
}else{
_objB.filters=[];
}
Each time AABSTest returns true, the intersected sphere is highlighted with a red glow: