In this assignment, we had to write a program to detect collisions among many sphere-like objects moving inside a confined region.
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 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 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.
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.
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.
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.
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 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.
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.