Assume we have an AABB, B, defined by a center point, c
Now, we want to test B against a plane n·x+d=0
(22.18)
e=hx|nx|+hy|ny|+hz|nz|. Why is this equivalent to finding the maximum of the eight different half diagonals projections? These eight half diagonals are the combinations: gi=(±hx,±hy,±hz)
Next, we compute the signed distance, s, from the center point, c
Testing an OBB against a plane differs only slightly from the AABB/plane test from the previous section. It is only the computation of the “extent” of the box that needs to be changed, which is done as
(22.19)
e=hBu|n·bu|+hBv|n·bv|+hBw|n·bw|.Recall that (bu,bv,bw)
Since graphics hardware uses the triangle as its most important (and optimized) drawing primitive, it is only natural to perform collision detection tests on this kind of data as well. So, the deepest levels of a collision detection algorithm typically have a routine that determines whether or not two triangles intersect. Given two triangles, T1=▵p1p2p3
From a high level, it is common to start by checking whether T1
In this implementation, there is heavy use of 4×4
(22.20)
[a,b,c,d]=-|axbxcxdxaybycydyazbzczdz1111|=(d-a)·((b-a)×(c-a)).Geometrically, Equation 22.20 has an intuitive interpretation. The cross product, (b-a)×(c-a)
We first test whether T1
At this point, two intervals, I1=[i,j]
(22.21)
[p1,p2,q1,q2]≤0and[p1,p3,q3,q1]≤0.The entire test starts with six determinant tests, and the first three share the first arguments, so many computations can be shared. In principle, the determinant can be computed using many smaller 2×2
If the triangles are coplanar, they are projected onto the axis-aligned plane where the areas of the triangles are maximized (Section 22.9). Then, a simple two-dimensional triangle-triangle overlap test is performed. First, test all closed edges (i.e., including endpoints) of T1
Note that the separating axis test (see page 947) can be used to derive a triangle/triangle overlap test. We instead presented a test by Guigue and Devillers [622], which is faster than using SAT. Other algorithms exist for performing triangle/triangle intersection [713,1619,1787] as well. Architectural and compiler differences, as well as variation in expected hit ratios, mean that we cannot recommend a single algorithm that always performs best. Note that precision problems can occur as with any geometrical tests. Robbins and Whitesides [1501] use the exact arithmetic by Shewchuk [1624] to avoid this.
This section presents an algorithm for determining whether a triangle intersects an axis-aligned box. Such a test is useful for voxelization and for collision detection.
Green and Hatch [581] present an algorithm that can determine whether an arbitrary polygon overlaps a box. Akenine-Möller [21] developed a faster method that is based on the separating axis test (page 947), and which we present here. Triangle/sphere testing can also be performed using this test, see Ericson’s article [440] for details.
We focus on testing an axis-aligned bounding box (AABB), defined by a center c
As soon as a separating axis is found the algorithm terminates and returns “no overlap.” If all tests pass, i.e., there is no separating axis, then the triangle overlaps the box.
Here we derive one of the nine tests, where i=0
(22.22)
p0=a·v0=(0,-f0z,f0y)·v0=v0zv1y-v0yv1z,p1=a·v1=(0,-f0z,f0y)·v1=v0zv1y-v0yv1z=p0,p2=a·v2=(0,-f0z,f0y)·v2=(v1y-v0y)v2z-(v1z-v0z)v2y.Normally, we would have had to find min(p0,p1,p2)
After the projection of the triangle onto a
(22.23)
r=hx|ax|+hy|ay|+hz|az|=hy|ay|+hz|az|,where the last step comes from that ax=0
(22.24)
if(min(p0,p2)>rormax(p0,p2)<-r)returnfalse;Code is available on the web [21].
The purpose of a bounding volume is to provide simpler intersection tests and make more efficient rejections. For example, to test whether or not two cars collide, first find their BVs and test if these overlap. If they do not, then the cars are guaranteed not to collide (which we assume is the most common case). We then have avoided testing each primitive of one car against each primitive of the other, thereby saving computation.
A fundamental operation is to test whether or not two bounding volumes overlap. Methods of testing overlap for the AABB, the k-DOP, and the OBB are presented in the following sections. See Section 22.3 for algorithms that form BVs around primitives.
The reason for using more complex BVs than the sphere and the AABB is that more complex BVs often have a tighter fit. This is illustrated in Figure 22.22. Other bounding volumes are possible, of course. For example, cylinders and ellipsoids are sometimes used as bounding volumes for objects. Also, several spheres can be placed to enclose a single object [782,1582].
For capsule and lozenge BVs it is a relatively quick operation to compute the minimum distance. Therefore, they are often used in tolerance verification applications, where one wants to verify that two (or more) objects are at least a certain distance apart. Eberly [404] and Larsen et al. [979] derive formulae and efficient algorithms for these types of bounding volumes.
For spheres, the intersection test is simple and quick: Compute the distance between the two spheres’ centers and then reject if this distance is greater than the sum of the two spheres’ radii. Otherwise, they intersect. In implementing this algorithm, it is best to use the squared distances of these two quantities, since all that is desired is the result of the comparison. In this way, computing the square root (an expensive operation) is avoided. Ericson [435] gives SSE code for testing four separate pairs of spheres simultaneously.
An algorithm for testing whether a sphere and an AABB intersect was first presented by Arvo [70] and is surprisingly simple. The idea is to find the point on the AABB that is closest to the sphere’s center, c
Larsson et al. [982] present some variants of this algorithm, including a considerably faster SSE vectorized version. Their insight is to use simple rejection tests early on, either per axis or all at the start. The rejection test is to see if the center-to-box distance along an axis is greater than the radius. If so, testing can end early, since the sphere then cannot possibly overlap with the box. When the chance of overlap is low, this early rejection method is noticeably faster. What follows is the QRI (quick rejections intertwined) version of their test. The early out tests are at lines 4 and 7, and can be removed if desired.
For a fast vectorized (using SSE) implementation, Larsson et al. propose to eliminate most of the branches. The idea is to evaluate lines 3 and 6 simultaneously using the following expression:
(22.25)
e=max(amini-ci,0)+max(ci-amaxi,0). Normally, we would then update d as d=d+e2
Note that lines 1 and 2 can be implemented using a parallel SSE max function. Even though there are no early outs in this test, it is still faster than the other techniques. This is because branches have been eliminated and parallel computations used. Another approach to SSE is to vectorize the object pairs. Ericson [435] presents SIMD code to compare four spheres with four AABBs at the same time.
For sphere/OBB intersection, first transform the sphere’s center into the OBB’s space. That is, use the OBB’s normalized axes as the basis for transforming the sphere’s center. Now this center point is expressed relative to the OBB’s axes, so the OBB can be treated as an AABB. The sphere/AABB algorithm is then used to test for intersection.
Larsson [983] gives an efficient method for ellipsoid/OBB intersection testing. First, both objects are scaled so that the ellipsoid becomes a sphere and the OBB a parallelepiped. Sphere/slab intersection testing can be performed for quick acceptance and rejection. Finally, the sphere is tested for intersection with only those parallelograms facing it.
An AABB is, as its name implies, a box whose faces are aligned with the main axis directions. Therefore, two points are sufficient to describe such a volume. Here we use the definition of the AABB presented in Section 22.2.
Due to their simplicity, AABBs are commonly employed both in collision detection algorithms and as bounding volumes for the nodes in a scene graph. The test for intersection between two AABBs, A and B, is trivial and is summarized below:
Lines 1 and 2 loop over all three standard axis directions x, y, and z. Ericson [435] provides SSE code for testing four separate pairs of AABBs simultaneously.
The intersection test for a k-DOP with another k-DOP consists of only k / 2 interval overlap tests. Klosowski et al. [910] have shown that, for moderate values of k, the overlap test for two k-DOPs is an order of magnitude faster than the test for two OBBs. In Figure 22.4 on page 946, a simple two-dimensional k-DOP is depicted. Note that the AABB is a special case of a 6-DOP where the normals are the positive and negative main axis directions. OBBs are also a form of 6-DOP, but this fast test can be used only when the two OBBs share the same axes.
The intersection test that follows is simple and extremely fast, inexact but conservative. If two k-DOPs, A and B (superscripted with indices A and B), are to be tested for intersection, then test all parallel pairs of slabs (SAi,SBi)
If at any time si=∅
Note that only k scalar values need to be stored with each instance of the k-DOP (the normals, ni
Laine and Karras [965] present an extension to k-DOPs called the apex point map. The idea is to map a set of plane normals to various points on the k-DOP, such that each point stored represents the most distant location along that direction. This point and the direction form a plane that fully contains the model in one half-space, i.e., the point is at the apex of the model’s k-DOP. During testing, the apex point retrieved for a given direction can be used for a more accurate intersection test between k-DOPs, for improved frustum culling, and for finding tighter AABBs after rotation, as some examples.
In this section we briefly outline a fast method for testing intersection between two OBBs, A and B [436,576,577]. The algorithm uses the separating axis test, and is about an order of magnitude faster than previous methods, which use closest features or linear programming. The definition of the OBB may be found in Section 22.2.
The test is done in the coordinate system formed by A’s center and axes. This means that the origin is ac=(0,0,0)
According to the separating axis test, it is sufficient to find one axis that separates A and B to be sure that they are disjoint (do not overlap). Fifteen axes have to be tested: three from the faces of A, three from the faces of B, and 3·3=9
As has been seen in Section 19.4, hierarchical view frustum culling is essential for rapid rendering of a complex scene. One of the few operations called during bounding-volume-hierarchy cull traversal is the intersection test between the view frustum and a bounding volume. These operations are thus critical to fast execution. Ideally, they should determine whether the BV is fully inside (inclusion), it is entirely outside (exclusion), or it intersects the frustum.
To review, a view frustum is a pyramid that is truncated by a near and a far plane (which are parallel), making the volume finite. In fact, it becomes a polyhedron. This is shown in Figure 22.24, where the names of the six planes, near, far, left, right, top, and bottom also are marked. The view frustum volume defines the parts of the scene that should be visible and thus rendered (in perspective for a pyramidal frustum).
The most common bounding volumes used for internal nodes in a hierarchy (e.g., a scene graph) and for enclosing geometry are spheres, AABBs, and OBBs. Therefore frustum/sphere and frustum/AABB/OBB tests will be discussed and derived here.
To see why we need the three return results outside/inside/intersect, we will examine what happens when traversing the bounding volume hierarchy. If a BV is found to be entirely outside the view frustum, then that BV’s subtree will not be traversed further and none of its geometry will be rendered. On the other hand, if the BV is fully inside, then no more frustum/BV tests need to be computed for that subtree and every renderable leaf will be drawn. For a partially visible BV, i.e., one that intersects the frustum, the BV’s subtree is tested recursively against the frustum. If the BV is for a leaf, then that leaf must be rendered.
The complete test is called an exclusion/inclusion/intersection test. Sometimes the third state, intersection, may be considered too costly to compute. In this case, the BV is classified as “probably inside.” We call such a simplified algorithm an exclusion/inclusion test. If a BV cannot be excluded successfully, there are two choices. One is to treat the “probably inside” state as an inclusion, meaning that everything inside the BV is rendered. This is often inefficient, as no further culling is performed. The other choice is to test each node in the subtree in turn for exclusion. Such testing is often without benefit, as much of the subtree may indeed be inside the frustum. Because neither choice is particularly good, some attempt at quickly differentiating between intersection and inclusion is often worthwhile, even if the test is imperfect.
It is important to realize that the quick classification tests do not have to be exact for scene-graph culling, just conservative. For differentiating exclusion from inclusion, all that is required is that the test err on the side of inclusion. That is, objects that should actually be excluded can erroneously be included. Such mistakes simply cost extra time. On the other hand, objects that should be included should never be quickly classified as excluded by the tests, otherwise rendering errors will occur. With inclusion versus intersection, either type of incorrect classification is usually legal. If a fully included BV is classified as intersecting, time is wasted testing its subtree for intersection. If an intersected BV is considered fully inside, time is wasted by rendering all objects, some of which could have been culled.
Before we introduce the tests between a frustum and a sphere, AABB, or OBB, we shall describe an intersection test method between a frustum and a general object. This test is illustrated in Figure 22.25. The idea is to transform the test from a BV/frustum test to a point/volume test. First, a point relative to the BV is selected. Then the BV is moved along the outside of the frustum, as closely as possible to it without overlapping. During this movement, the point relative to the BV is traced, and its trace forms a new volume (a polygon with thick edges in Figure 22.25). The fact that the BV was moved as close as possible to the frustum means that if the point relative to the BV (in its original position) lies inside the traced-out volume, then the BV intersects or is inside the frustum. So, instead of testing the BV for intersection against a frustum, the point relative to the BV is tested against another new volume, which is traced out by the point. In the same way, the BV can be moved along the inside of the frustum and as close as possible to the frustum. This will trace out a new, smaller frustum with planes parallel to the original frustum [83]. If the point relative to the object is inside this new volume, then the BV is fully inside the frustum. This technique is used to derive tests in the subsequent sections. Note that the creation of the new volumes is independent of the position of the actual BV—it is dependent solely on the position of the point relative to the BV and the shape of the BV. This means that a BV with an arbitrary position can be tested against thesame volumes.
Saving just a parent BV’s intersection state with each child is a useful optimization. If the parent is known to be fully inside the frustum, none of the descendants need any further frustum testing. The plane masking and temporal coherence techniques discussed in Section can also noticeably improve testing against a bounding volume hierarchy, though are less useful with a SIMD implementation [529].
First, we derive the plane equations of the frustum, since these are needed for these sorts of tests. Frustum/sphere intersection is presented next, followed by an explanation of frustum/box intersection.
To do view frustum culling, the plane equations for the six different sides of the frustum are needed. We present here a clever and fast way of deriving these. Assume that the view matrix is V
Focus for a moment on the volume on the right side of the left plane of the unit cube, for which -1≤ux
(22.26)
-1≤ux⟺-1≤txtw⟺tx+tw≥0⟺⟺(m0,·s)+(m3,·s)≥0⟺(m0,+m3,)·s≥0.In the derivation, mi,
(22.27)
-(m3,+m0,)·(x,y,z,1)=0[left],[2pt]-(m3,-m0,)·(x,y,z,1)=0[right],[2pt]-(m3,+m1,)·(x,y,z,1)=0[bottom],[2pt]-(m3,-m1,)·(x,y,z,1)=0[top],[2pt]-(m3,+m2,)·(x,y,z,1)=0[near],[2pt]-(m3,-m2,)·(x,y,z,1)=0[far].Code for doing this in OpenGL and DirectX is available on the web [600].
A frustum for an orthographic view is a box, so the overlap test in this case becomes a sphere/OBB intersection and can be solved using the algorithm presented in Section 22.13.2. To further test whether the sphere is entirely inside the box, we first check if the sphere’s center is between the box’s boundaries along each axis by a distance greater than its radius. If it is between these in all three dimensions, it is fully contained. For an efficient implementation of this modified algorithm, along with code, see Arvo’s article [70].
Following the method for deriving a frustum/BV test, for an arbitrary frustum we select the center of the sphere as the point p
Assume that the plane equations of the frustum are such that the positive half-space is located outside of the frustum. Then, an actual implementation would loop over the six planes of the frustum, and for each frustum plane, compute the signed distance from the sphere’s center to the plane. This is done by inserting the sphere center into the plane equation. If the distance is greater than the radius r, then the sphere is outside the frustum. If the distances to all six planes are less than -r
To make the test more accurate, it is possible to add extra planes for testing if the sphere is outside. However, for the purposes of quickly culling out scene-graph nodes, occasional false hits simply cause unnecessary testing, not algorithm failure, and this additional testing will cost more time overall. Another more accurate, though still imprecise, method is described in Section 20.3, useful for when these sharp corner areas are significant.
For efficient shading techniques, the frusta are often highly asymmetrical and a special method for that is described in Figure 20.7 on page 895. Assarsson and Möller [83] provide a method that eliminates three planes from each test by dividing the frustum into octants and finding in which octant the center of the object is located.
If the view’s projection is orthographic (i.e., the frustum has a box shape), precise testing can be done using OBB/OBB intersection testing (Section 22.13.5). For general frustum/box intersection testing, there are two methods commonly used. One simple method is to transform all eight box corners to the frustum’s coordinate system by using the view and projection matrices for the frustum. Perform clip testing for the canonical view volume that extends [-1,1]
A method that is considerably more efficient on the CPU is to use the plane/box intersection test described in Section 22.10. Like the frustum/sphere test, the OBB or AABB is checked against the six view frustum planes. Instead of computing the signed distance of all eight corners from a plane, in the plane/box test we check at most two corners, determined by the plane’s normal. If the nearest corner is outside the plane, the box is fully outside and testing can end early. If the farthest corner for every plane is inside, then the box is contained inside the frustum. Note that the dot product distance computations for the near and far planes can be shared, since these planes are parallel. The only additional cost for this second method is that the frustum’s planes must first be derived, a trivial expense if a few boxes are tobe tested.
Like the frustum/sphere algorithm, the test suffers from classifying boxes as intersecting that are actually fully outside. Those kinds of errors are shown in Figure 22.27. Quílez [1452] notes that this can happen more frequently with fixed-size terrain meshes or other large objects. When an intersection is reported, his solution is to then also test the corners of the frustum against each of the planes forming the bounding box. If all points are outside a box’s plane, the frustum and box do not intersect. This additional test is equivalent to the second part of the separating axis test, where the axis tested is orthogonal to the second object’s faces. That said, such additional testing can be more costly than the benefits accrued. For his GIS renderer, Eng [425] found that this optimization cost 2 ms per frame of CPU time to save only a few draw calls.
Wihlidal [1884] goes the other direction with frustum culling, using only the four frustum side planes and not performing the near and far plane cull tests. He notes that these two planes do not help much in video games. The near plane is mostly redundant, since the side planes trim out almost all the space it does, and the far plane is normally set to view all objects in the scene.
Another approach is to use the separating axis test (found in Section 22.13) to derive an intersection routine. Several authors use the separating axis test for a general solution for two convex polyhedra [595,1574]. A single optimized test can then be used for any combination of line segments, triangles, AABBs, OBBs, k-DOPs, frusta, and convex polyhedra.
In this section, both two- and three-dimensional line/line intersection tests are derived and examined. Lines, rays, and line segments are intersected with one another, and methods that are both fast and elegant are described.
From a theoretical viewpoint, this first method of computing the intersection between a pair of two-dimensional lines is truly beautiful. Consider two lines, r1(s)=o1+sd1
(22.28)
1:r1(s)=r2(t)⟺2:o1+sd1=o2+td2⟺3:{sd1·d⊥2=(o2-o1)·d⊥2td2·d⊥1=(o1-o2)·d⊥1⟺4:{s=(o2-o1)·d⊥2d1·d⊥2t=(o1-o2)·d⊥1d2·d⊥1If d1·d⊥2=0
Antonio [61] describes another way of deciding whether two line segments (i.e., of finite length) intersect by doing more compares and early rejections and by avoiding the expensive calculations (divisions) in the previous formulae. This method is therefore faster. The previous notation is used again, i.e., the first line segment goes from p1
(22.29)
{s=-c·a⊥b·a⊥=c·a⊥a·b⊥=df,t=c·b⊥a·b⊥=ef.In Equation 22.29, a=q2-q1
After this test, it is guaranteed that 0≤s≤1
Source code for an integer version of this routine is available on the web [61], and is easily converted for use with floating point numbers.
Say we want to compute in three dimensions the intersection between two lines (defined by rays, Equation 22.1). The lines are again called r1(s)=o1+sd1
(22.30)
1:r1(s)=r2(t)[2pt]⟺[2pt]2:o1+sd1=o2+td2[2pt]⟺[2pt]3:{sd1×d2=(o2-o1)×d2td2×d1=(o1-o2)×d1[2pt]⟺[2pt]4:{s(d1×d2)·(d1×d2)=((o2-o1)×d2)·(d1×d2)t(d2×d1)·(d2×d1)=((o1-o2)×d1)·(d2×d1)[2pt]⟺[2pt]5:{s=det(o2-o1,d2,d1×d2)||d1×d2||2t=det(o2-o1,d1,d1×d2)||d1×d2||2Step 3 comes from subtracting o1
Goldman [548] notes that if the denominator ||d1×d2||2
If the lines are to be treated like line segments, with lengths l1
Rhodes [1490] gives an in-depth solution to the problem of intersecting two lines or line segments. He gives robust solutions that deal with special cases, and he discusses optimizations and provides source code.
Given three planes, each described by a normalized normal vector, ni
(22.31)
p=(p1·n1)(n2×n3)+(p2·n2)(n3×n1)+(p3·n3)(n1×n2)|n1n2n3|.This formula can be used to compute the corners of a BV consisting of a set of planes. An example is a k-DOP, which consists of k plane equations. Equation 22.31 can calculate the corners of the convex polyhedron if it is fed with the proper planes.
If, as is usual, the planes are given in implicit form, i.e., πi:ni·x+di=0 , then we need to find the points pi in order to be able to use the equation. Any arbitrary point on the plane can be chosen. We compute the point closest to the origin, since those calculations are inexpensive. Given a ray from the origin pointing along the plane’s normal, intersect this with the plane to get the point closest to the origin:
(22.32)
ri(t)=tnini·x+di=0}⇒ni·ri(t)+di=0⟺tni·ni+di=0⟺t=-di⇒pi=ri(-di)=-dini.This result should not come as a surprise, since di in the plane equation simply holds the perpendicular, negative distance from the origin to the plane (the normal must be of unit length if this is to be true).
Ericson’s Real-Time Collision Detection [435] and Eberly’s 3D Game Engine Design [404] cover a wide variety of object/object intersection tests and hierarchy traversal methods, along with much else, and include source code. Schneider and Eberly’s Geometric Tools for Computer Graphics [1574] provides many practical algorithms for two- and three-dimensional geometric intersection testing. The open-access Journal of Computer Graphics Techniques publishes improved algorithms and code for intersection testing. The older Practical Linear Algebra [461] is a good source for two-dimensional intersection routines and many other geometric manipulations useful in computer graphics. The Graphics Gems series [72,540,695,902,1344] includes many different kinds of intersection routines, and code is available on the web. The free Maxima [1148] software is good for manipulating equations and deriving formulae. This book’s website includes a page, http://www.w3.org/1999/xlink, summarizing resources available for many object/object intersection tests.
1 This test is sometimes known as the “separating axis theorem” in computer graphics, a misnomer we helped promulgate in previous editions. It is not a theorem itself, but is rather a special case of the separating hyperplane theorem.
2 The scalar r2 could be computed once and stored within the data structure of the sphere in an attempt to gain further efficiency. In practice such an “optimization” may be slower, as more memory is then accessed, a major factor for algorithm performance.