Collision Detection Between Rigid Bodies


In this assignment, we had to write a program to detect collisions among many sphere-like objects moving inside a confined region.

Part A: Implementation

I implemented this project using the collision detection package SWIFT++. The scene consists of a bounding cube that contains many sphere-like objects moving around and colliding with each other. The sphere-like objects are varying approximations of a sphere with different numbers of polygons. I used 6-, 80-, 320-, 1280-, and 5120-face approximations. Each object is given a random initial linear velocity and angular velocity, and their motion is computed using Euler integration. Here is a screenshot of the program:

Collision detection

Collision detection was done using various SWIFT++ queries. I implemented collision detection using two different schemes. The first scheme is simply tolerance verification (SWIFT++'s Query_Tolerance_Verification call): whenever two objects came closer than the maximum velocity times the time step, they were considered to be colliding. This technique was very simple and intuitive, and produced decent results. However, using this technique, objects can interpenetrate before they are considered colliding, which can sometimes look odd and generate incorrect results. In this case, this was not much of a problem, but in more complex systems it would matter more.

The second scheme I implemented used SWIFT++'s Query_Contact_Determination call. This query is used to find contact information between objects that are close in the scene, such as the contact normal and the closest features. In order to use this call, I first called Query_Intersection to determine which objects in the scene were intersecting. I then set the time back by one time step (as a precursor to the bisection method, which I did not implement) and used the objects' states at that time to perform collision response based upon their contact normal. This technique is clearly much slower than the first technique, but with a full bisection method implementation (or better) it will eventually generate better results for collision response.

Collision response

Collision response in my program is very simple. The angular velocity of each object remains constant. When two objects collide, I determine their new velocities based on conservation of linear momentum. When using tolerance verification, I calculate the contact normal between two sphere-like objects as the vector between their centers of mass. When using contact determination, I use the normal information returned by the function call.

Other implementation notes

I slightly modified SWIFT++ to allow access to some of its internal data. This allowed me to share mesh information so that I would not have to store it separately for rendering purposes. The code for my program can be downloaded here.

Part B: Analysis

For most of my analysis, I used the tolerance verification technique since it was considerably faster and there were not any major problems with it for this application. The analysis involved changing various parameters: the number of objects, the complexity of the objects, and the sizes of the objects. These are explored below. All tests were done by running 1000 iterations of the simulation.

Changing the number of objects

As expected, increasing the number of objects in the scene causes collision detection to take longer, particularly because adding more objects in a confined region will cause many more collisions to occur. SWIFT++ does a nice job of keeping this time increase low, however. Below is a graph showing the average time for an iteration in the program for various numbers of objects. Each object had 320 faces, except where noted in the graph (one run made each object have a random tessellation level).

The next graph shows the same thing as above, but instead each object has a random tessellation level. The original trend is still followed, but the graphs are slightly more erratic as the objects are more varied here than in the first case.

Changing the complexity of the objects

In order to determine what effect changing the object complexity had on collision detection performance, I tested using five different complexity levels of sphere-like objects. The graph below shows that increasing the complexity (and the number of objects) also increases the time required to perform collision detection. This makes sense, as a lot more comparisons have to be made in order to determine if objects are intersecting. Since all the objects are sphere-like, bounding volumes can easily be constructed and performance does not suffer too much by increasing the object complexity.

Changing the sizes of the objects

Changing the size of the objects did not affect the performance of collision detection much. As the sizes of the objects are increased relative to the size of the outer bounding cube, the average time per iteration increases, since collisions become more likely in a confined space with large objects. As is shown in the graph below, increasing the radius of the objects as well as the number of objects caused the average time to increase, but not by very much.

Part C: Varying Parameters, Optimization

If we know that all of the objects in the scene are of the same size, what can be done to optimize collision detection? The first thing that comes to mind is to uniformly subdivide the space within the outer boundary cube. If we divide space into a 3D grid with cells of side length equal to or slightly larger than the diameter of the objects, then each object can reside in or intersect with at most 8 distinct cells in the grid. Collision detection only needs to be performed between object pairs that lie within the same cells. Those objects that do not lie within the same cells do not need to be compared for intersection and can be culled from the collision detection iteration. This can lead to substantial savings in theory. I implemented a uniform spatial subdivision grid to test this out. At first, I was not getting much out of this technique, presumably because SWIFT++ is already very optimized and repeatedly calling its Deactivate and Activate functions is not very efficient. However, as I increased the number of objects in the scene, the grid seemed to help after a certain point. I tested this using both the tolerance verification method and the contact determination method (as it's much slower and the difference can be seen more easily). The graph below shows the results for the tolerance verification method. After about 55 objects, the spatial subdivision grid seems to provide better performance.

The next graph shows the results for the contact determination method. The benefits of using the spatial subdivision grid can be seen much earlier, at around 25 objects.

Note that using the grid causes the graph to increase relatively linearly.