AABB Trees: Best Axis Algorithm

December 3rd, 2007

Created: Aug 4, ‘04

Printer Friendly

AABB Trees: Best Axis Algorithm

Hopefully you have read my tutorial on computing AABBs. We will now build on that knowledge and build an AABB Tree. AABB Trees provide accurate collision detection for complex scenes/polygon soups (and it can be used for culling too). This paper focuses on using AABB Trees for collision detection.


Below is an example of a mesh using an AABB Tree:
AABB Trees are hierarchial structures that consist of AABB Nodes. Each AABB Node has it’s own min/max bound and pointer members to left/right AABB Nodes. Below is a definition of an AABB Node:

	struct AABBNode
	{
		WVector min, max;
		AABBNode *left, *right;
		WVector *m_pVerts;	//vertices stored within this node
		unsigned int m_nNumVerts; //num of vertices stored (3->n)
	};

The AABBB Tree is composed of AABBNode primitives. To compute an AABB Tree, we use a heuristic (inputs to the algorithm) that defines the max tree depth and minimum number of vertices we want each node to contain.

	typedef unsigned int udword;  

	//Defines the behavior of the AABB tree
	struct GODZ_API AABBTreeInfo
	{
		//heuristics
		udword max_tree_depth;		//max depth the tree can reach
		//min number of vertices each leaf can store
		udword min_vertices;		  

		//ensures that an AABB is never generated that
		//is over min_vertices. Normally, this algorithm
		//is not required because the best axis
		//algorithm normally produces a perfectly balanced tree.
		bool m_bPrune;
	};

The typical AABB Tree can store any number of vertices at each leaf. The heuristic can be played around with to determine best performance (triangles vs max tree depth). The more triangles you store within each node, the less AABB nodes you’ll end up with. If you store too few vertices, you may end up with a huge AABB Tree consisting of lots of nodes. If you store too many triangles, you might end up with too few AABB Nodes- which may cause you too spend too much time evaluating a collision with triangles. During the building process, we recursively crunch the vertex buffer until we end up with a tree that holds an AABB for triangle(s) within the mesh. An AABB Tree is composed of two different types of tree nodes: parent and leaf nodes. The parent AABB Node simply references left/right siblings. It’s AABB encloses it’s child AABB Nodes but it is only an indicator that a collision may be possible. We recursively descend into the AABB tree until we find child leaf nodes that directly store triangles. Below we define the structure of the AABB Tree:

	struct AABBTree
	{
		AABBNode *root;
	};

AABB Trees are normally computed using the longest axis of the box. From there, we examine each triangle in the vertex buffer and test the center of the face to see if it’s less/greater than the split. If it’s less, then we can place the triangle in the buffer for the left node. If it’s greater than we can place this triangle in the right buffer. So basically we just split the VB (vertex buffer) and generate the right/left AABB node. However, instead of using simply the longest axis of the box, we can instead pick the best axis of the box that will result in the most balanced tree. We find the best axis of a vertex buffer by using the C++ code below:

int AABBNode::FindBestAxis(std::vector<Vertex> &vertexList)
{
	size_t vertexNum=vertexList.size();  

	//divide this box into two boxes - pick a better axis
	int iAxis=0;
	int iAxisResult[3]; //stores how close end result is, the lower the better  

	WVector center = m_box.GetCenter();  

	for (iAxis=0;iAxis<3;iAxis++)
	{
		int left=0,right=0;
		Vertex v[3];
		int count=0;
		for(udword i=0;i<vertexNum;i++)
		{
			v[count]=vertexList[i];
			if (count==2)
			{
				float faceCenter[3];
				faceCenter[0] = (v[0].x + v[1].x + v[2].x) / 3.0f;
				faceCenter[1] = (v[0].y + v[1].y + v[2].y) / 3.0f;
				faceCenter[2] = (v[0].z + v[1].z + v[2].z) / 3.0f;  

				if (faceCenter[iAxis] <= center[iAxis])
				{
					left++;
				}
				else
				{
					right++;
				}  

				count=0;
			}
			else
			count++;
		} // vertices  

		iAxisResult[iAxis] = abs(left-right);
	} //axis  

	int index=0;
	int result=iAxisResult[0];
	for (int i=1;i<3;i++)
	{
		if (iAxisResult[i] < result)
		{
			result = iAxisResult[i];
			index=i;
		}
	}  

	//Log("result: %d\n", iAxisResult[index]);  

	return index;
}

We call the FindBestAxis() during the tree building process. Below is the C++ code to build the AABB Tree. It is recursive, recuring only one simple call to start the process.

void AABBNode::BuildTree(vector<Vertex> vertexList, AABBTreeInfo &treeInfo,
udword depth)
{
	int vertexNum=(int)vertexList.size();  

	// Build the node bounding box based from the triangle list
	WBox Box(&vertexList[0], vertexNum);  

	//debug box bounds
	SetBounds(Box);  

	if (depth+1 > treeInfo.curr_max_depth)
		treeInfo.curr_max_depth=depth+1;  

	bool bMakeChildren=false;  

	if (vertexNum > treeInfo.min_vertices
	&& depth<treeInfo.max_tree_depth)
	{
		bMakeChildren=true;
	}  

	if (bMakeChildren)
	{
        // Find the longest axii of the node's box
		//int iAxis=Box.GetLongestAxis();
		int iAxis = FindBestAxis(vertexList);
		//Log("Longest axis: %d\n", iAxis);  

		//Get the Arrays for min, max dimensions
		float *min = &Box.min.x;
		float *max = &Box.max.x;  

		//get center of the box for longest axis
		//float fSplit = ( max[ iAxis ] + min[ iAxis ] ) / 2.f ;
		WVector center = Box.GetCenter();
		//Log("split: %f\n", fSplit);  

		int count=0;
		Vertex v[3];
		vector<Vertex> leftSide;
		vector<Vertex> rightSide;  

		udword leftCount=0,rightCount=0; //debug  

		//Log("verts: %d\n", vertexNum);  

		//btw, things that could go wrong- if the mesh doesn't
		//send over the triangles correctly, then you might see
		//huge boxes that are misaligned (bad leaves).
		//things to check is making sure the vertex buffer is
		//correctly aligned along the adjancey buffers, etc
		for(int i=0;i<vertexNum;i++)
		{
			v[count] = vertexList[i];  

			if (count==2)
			{
				float faceCenter[3];
				faceCenter[0] = (v[0].x + v[1].x + v[2].x) / 3.0f;
				faceCenter[1] = (v[0].y + v[1].y + v[2].y) / 3.0f;
				faceCenter[2] = (v[0].z + v[1].z + v[2].z) / 3.0f;
				//WVector faceCenter(x,y,z);  

				if (faceCenter[iAxis] <= center[iAxis]) //fSplit
				{
					//Store the verts to the left.
					leftSide.push_back(v[0]);
					leftSide.push_back(v[1]);
					leftSide.push_back(v[2]);  

					leftCount++;
				}
				else
				{
					//Store the verts to the right.
					rightSide.push_back(v[0]);
					rightSide.push_back(v[1]);
					rightSide.push_back(v[2]);  

					rightCount++;
				}  

				count=0;
			}
			else
				count++;
		}  

		if (treeInfo.m_bPrune && (leftCount == 0 || rightCount == 0)
			)
		{
			//okay, now it's time to cheat. we couldn't use
			//the best axis to split the
			//box so now we'll resort to brute force hacks....
			leftSide.clear();
			rightSide.clear();  

			int leftMaxIndex = vertexNum / 2; //left side  

			int count=0;
			Vertex v[3];
			for(int i=0;i < vertexNum;i++)
			{
				v[count] = vertexList[i];
				if (count == 2)
				{
					if (i<leftMaxIndex)
					{
						//left node
						leftSide.push_back(v[0]);
						leftSide.push_back(v[1]);
						leftSide.push_back(v[2]);
					}
					else
					{
						rightSide.push_back(v[0]);
						rightSide.push_back(v[1]);
						rightSide.push_back(v[2]);
					}  

					count=0;
				}
				else
					count++;
			}
		}  

		if (leftSide.size() > 0 && rightSide.size() > 0)
		{
			assert(leftSide.size() % 3 == 0);
			assert(rightSide.size() % 3 == 0);  

			//Build child nodes
			if (leftSide.size() > 0)
			{
				treeInfo.left_children++;
				children[0] = new AABBNode(leftSide,
				treeInfo, depth+1);
			}
			if (rightSide.size() > 0)
			{
				treeInfo.right_children++;
				children[1] = new AABBNode(rightSide,
				treeInfo, depth+1);
			}
		}
		else
		{
			//should never happen
			bMakeChildren=false;
		}
	}  

	if (!bMakeChildren)
	{
		//Store the data directly if you want....
	}
}

This is really all it takes to construct an AABB Tree. You will also of course need functions to perform AABB Overlap tests and AABB Sweeps. This is the logic to detect collision using the AABB Tree:

  • Test other AABB against the root of the AABB Tree. If it does not overlap then return false. If it does, proceed.
  • If the AABB Node is a leaf, then return true. If not, proceed.
  • Call the left AABB Node and recursively check it’s child nodes to see if any or
    leaves and if one of them collides with the AABB Node.
  • If no collisions have been detected then check the right AABB Node. If it or
    one of it’s nodes is a leaf node and it overlaps the AABB then return true.

Below is C++ code of an AABB Node performing an AABB Sweep (you might want to read up on Sweep Volumes).

bool AABBNode::AABBSweepHit(CollisionPrimitive *A, const WVector &oldLocation,

const WVector &newLocation, CollisionResult &result)
{
//if the box is impact by the moving primitive
if (CollisionPrimitive::AABBSweepHit(A, oldLocation, newLocation, result))
{
if (IsLeaf())
{
//test all the triangles within the this node.
//Verify a collision exists.
}

//Go through children since this is not a leaf
AABBNode *left = GetLeftChild();
AABBNode *right = GetRightChild();

if (left != NULL && left->AABBSweepHit(A, oldLocation,
newLocation, result))
{
return true;
}

if (right != NULL && right->AABBSweepHit(A, oldLocation,
newLocation, result))
{
return true;
}
}

return false;
}
 

AABB Trees, Where are they getting used?
Many games uses different forms of bounding volume hierarchies. I talked with a guy that worked on Ratchet and Clank, which I hear used Sphere Volume Trees (which is the same as AABB Trees just that pills are used instead of boxes). The Unreal Engine uses an AABB Tree variant for static meshes. Static meshes- despite their name, can actually be moved around the level- so all of the child nodes get transformed along with the entity.

References:
3D Game Engine Design by David Eberly

  1. Uddin
    August 20th, 2008 at 10:53 | #1

    Hello,

    I am a postdoc in UCD, working on the minimum distance calculation between two objects.

    Could you please give me complete source codes for making sphere heirarchy tree? And, could you send me codes for proximity query between two objects by traversing their sphere trees?

    Your cooperation and useful suggestions regarding the above will be appreciated.

    Thank you.

    Regards,
    Uddin

  2. August 21st, 2008 at 09:13 | #2

    Sphere trees are fairly similar Uddin to an AABB Tree. Also, performing a query between two spheres in a Sphere tree shouldn’t be too bad if you code a regular brute force approach.

    This book might be of some use:
    http://www.amazon.com/Real-Time-Collision-Detection-Interactive-Technology/dp/1558607323

    good luck,
    -Richard

  3. Adam Corum
    September 15th, 2008 at 10:41 | #3

    I don’t see where you declared m_box in AABBNode

  4. Adam Corum
    September 15th, 2008 at 10:53 | #4

    Also, you reference center as an array in this line :

    if (faceCenter[iAxis] <= center[iAxis])

    I assume that you mean X as [0], Y as [1], and Z as [2]

  5. Adam Corum
    September 15th, 2008 at 11:14 | #5

    Also, on this chunk :

    if (leftSide.size() > 0 && rightSide.size() > 0)
    {
    assert(leftSide.size() % 3 == 0);
    assert(rightSide.size() % 3 == 0);

    //Build child nodes
    if (leftSide.size() > 0)
    {
    treeInfo.left_children++;
    children[0] = new AABBNode(leftSide,
    treeInfo, depth+1);
    }
    if (rightSide.size() > 0)
    {
    treeInfo.right_children++;
    children[1] = new AABBNode(rightSide,
    treeInfo, depth+1);
    }
    }
    else
    {
    //should never happen
    bMakeChildren=false;
    }

    }else

    The inner two if statements always evaluate to true because they are included in the outter if

  6. Adam Corum
    September 15th, 2008 at 11:17 | #6

    One more thing. You imply that AABBTreeInfo has these members:

    1) left_children
    2) right_children
    3) children

    but you neglected to show us that in you AABBTreeInfo definition.

  7. Adam Corum
    September 15th, 2008 at 11:32 | #7

    any chance you could post all the code?

  8. September 16th, 2008 at 23:11 | #8

    Yeah I’ll just post the code. About the “if” statement, that was just for the sake of the assert I believe. I think I did remove that from my current code.

    The m_box member in AABB Node is the collision. Each AABB Node stores an AABB.

    Only reason I am hesitant though to post the code from my engine- some thing might not make sense on their own. Wish I had time to put together a playable tutorial that just demonstrates the concept. Would make things clearer.

  9. Adam Corum
    September 17th, 2008 at 10:10 | #9

    If you can give me a good chunk of code that compiles on it’s own, I can make sense of it. I want to put together a physics engine for a talk I’ll be giving in a few months, and I have all the parts except rotation and collision detection. I don’t mind sifting through it at all.

  10. Adam Corum
    September 17th, 2008 at 10:12 | #10

    Oh if you don’t want post, I would be much obliged if you sent it to me directly at likwid38225@gmail.com
    That way you can circumvent questions you don’t want to answer to the general public.

  11. September 20th, 2008 at 23:22 | #11

    Well problem is the AABB Tree code is all tied into my engine demo. So, it won’t compile on its own. There are some good AABB Tree tutorials out there with full source code. Also, David Eberly may have AABB tree source on his web site.

    So you should be able to find some examples of Collision Trees that are runnable. Now to think of it I learned how to code an AABB Tree years ago from David Eberly’s book on Game Engine Design

  12. Adam Corum
    September 25th, 2008 at 17:12 | #12

    Thanks for the bare bones and explanation. I got it working. Well, mostly working but I have something to work with.

  13. liu
    July 31st, 2009 at 08:44 | #13

    hi,
    how to use the BuildTree()

  1. No trackbacks yet.