Rigid Body Simulation
with Collision Detection
Andrew G. Zaferakis
UNC Chapel Hill
COMP 236 Spring 2000

Project Final Report - Rigid Body Dynamics with Collisions
    Contents
  1. Rigid Body Implementation
  2. Collision Detection
  3. Sampling a Rigid Body
  4. Collision Rebound
  5. ODE Solver
  6. Performance Hints
  7. Future Research
  8. Conclusions
    The focus of my research into this area is mainly based on the collision detection problem, and not on the exact simulation of rigid body dynamics.  The first pass implementation of a rigid body simulator has been scrapped due to its unnecessary complexity.  The datastructures were geared for 3D and followed closely to David Baraff's SIGGRAPH '97 Course Notes.  Since this project is using 2D dynamics, the datastructures and solvers were performing unneeded computation and were bloated.  I decided to scrap the first system and replace it with a more streamlined second version.

class RigidBody
{
    Body      CenterMass;   // CENTER OF MASS
    Particles Samples;      // SAMPLING PARTICLES
}
class Body
{
    float  mass;            // MASS OF RIGID BODY
    float  position[2];     // x,y POSITION
    float  velocity[2];     // x,y LINEAR VELOCITY
    float  rotation;        // ROTATION IN DEGREES (z-axis)
    float  omega;           // ANGULAR VELOCITY (z-axis)
    float  force[2];        // x,y LINEAR FORCE
    float  torque;          // ANGULAR FORCE (z-axis)
}
typedef struct _Particle {
    float x,y;              // x,y POSITION RELATIVE TO CENTER MASS
} Particle;

class Particles
{
    int       NumParticles; // NUMBER OF PARTICLES
    Particle *P;            // ARRAY OF PARTICLES
}

    Looking at the various classes notice how the positions and velocities are stored for the x and y coordinates only.  Angular velocity (omega) and torque are implicitly defined for the z-axis, which is the axis of rotation in 2D.  In the previous system, I was storing vector and matrices, which are much larger and require more bookkeeping, which can be eliminated because there is no linear motion in the z-direction, and no rotation about the x-axis or y-axis.
    Using this streamlined version we can perform some tricks to speed up the simulation at the cost of some accuracy.  The description of how to compute rebound forces will be shown in detail later.

    Collision detection between objects is a critical component in a rigid body simulation.  A driving force in computer graphics is real-time dynamics.  Our new approach to collision detection is to use the voronoi diagram and depth buffer to query distance from an object.  Details of computing the hardware accelerated generalized voronoi diagram has been presented in full by Kenny Hoff et al, including its use for motion planning.  I have extended its use to collision detection for a rigid body simulation.  For this demonstration we are concerned with collision between a rigid body and a static object (voronoi site).  The individual rigid bodies are not included in the overall vornoi diagram.  Multiple rigid bodies may be in the simulation at one time, however they will not interact with each other, only with the voronoi sites.  A description of how to model multiple interacting rigid bodies is described in the "Future Research" section.

Color and Depth Buffer

    The basic principle behind using the voronoi diagram for collision detection is to use a two pass algorithm.  The first pass through the system will draw the voronoi sites, into the back buffer.  Each site has a distinct color which is used as its id.  The geometry behind the voronoi diagram will not be discussed here.  Each pixel has a distinct color and depth.  The depth value is the distance to the voronoi site whose id is the color at the pixel.  A rigid body is theoretically composed of particles.  A particle in the system exists at a single pixel, by reading back the depth buffer it can determine if it is colliding with an object.  If the distance is within a certain distance tolerance then there is a collision between the particle and the voronoi site.  By reading the color buffer at the pixel location, the particle then knows which voronoi site it is in contact with.  How to correctly sample a rigid body into particles will be discussed in the next section.  Images below show the voronoi sites and associated depth buffer.

(click to enlarge)

Color Buffer

Depth Buffer

    The image on the left shows three voronoi line sites (click on picture for full size).  If we think of the voronoi diagram as a force field that is stronger the closer a particle is to the actual site, the path of least resistance is along the voronoi boundaries.  This is easily visible in the depth buffer image, where darker values are farther away from the voronoi sites.

Storing Contacts

    When a collision is detected, we must break from the ordinary ordinary differential equation solver and compute the updates.  To do this we store the contacts in a class.

typedef struct _ContactPoint {
  RigidBody *rb;               // BODY CONTAINING VERTEX
  int        siteID;           // VORONOI SITE ID
  float      pos[2];           // WORLD-SPACE VERTEX LOCATION
  float      n[2];             // OUTWARDS POINTING NORMAL OF VORONOI SITE
} ContactPoint;

class Contact
{
public:
  int NumContacts;
  ContactPoint *C;
}

    This class will allow for multiple contacts per timestep, which is useful if the solver can handle them.  What should normally happen is that the solver will backup to the instant of the first contact and solve the appropriate forces.  In rigid body simulation only one contact can happen at a single timestep.

    After the voronoi diagram has been read and collisions detected, the scene can then be drawn over the top of the voronoi diagram.  We only need to have the voronoi diagram for collision detection, it does not need to be present for the actual drawing environment.  Rigid body's may have a geometric representation with texture mapping, as well as the voronoi sites.  This shows the advantages multipass rendering and how the graphics hardware can be used for many ways.

    To perform collision detection, a sample in the rigid body must collide with the voronoi site.  The accuracy of the collision detection is directly based upon the sampling of the rigid body.  Theoretically, the rigid body is composed of infinite sampling points, therefore always detecting the exact point of collision.  However, an infinite number of samples is not a realistic number in this system.   If we sample the rigid body sparsely, then an intersection between the rigid body and the voronoi site may go unnoticed.  Another serious problem is if the rigid body penetrates the site too far before a detection, then the calculated rebound may not be strong enough for the rigid body to separate from the voronoi site, causing another collision to be detected and causing the bodies to stick together.  The question is "How do I correctly sample my rigid body?"

(click to enlarge)

Sparse Boundary Sampling

Dense Boundary Sampling

    The answer is: "It depends on the situation!"  What if there is a simulation with many bodies, and some bodies require very accurate collision detection, and others do not, then a different sampling density for both bodies is needed.  What we want to do is allow the user to specify the sampling density for each rigid body at the start of the simulation.  This can be accomplished in various ways.  A simple way to do this is to have the user supply the sampling points in a datafile.  Below is a sample datafile for a square with 3 samples per edge, no samples in the interior (8 samples).

8                        // NUMBER OF SAMPLES
10    0 0   0 0  0  20   // CENTER MASS - MASS, X,Y, VX, VY, ROTATION, OMEGA
-0.3 -0.3
 0.0 -0.3
 0.3 -0.3
 0.3  0.0
 0.3  0.3
 0.0  0.3
-0.3  0.3
-0.3  0.0

    This allows the user to have to complete control over the sampling density.  This solution allows for specification of non-uniform sampling of arbitrary shaped objects, since the sampling is what essentially defines the boundary of the object.

Boundary vs. Volume Sampling

    Two different styles for sampling can be used, each providing their own set of benefits.  When simulating we can specify the timestep to be any value, therefore making it small enough to detect surface collision.  If this is the case, then we need to only sample the boundary of the rigid body.  Since we are detecting contact at the surface, any point inside the boundary will never be used, which is still being tested.  Eliminating the inner sampling points will dramatically reduce the computation per timestep since only the boundary is being tested.  For example, if we have a square rigid body with n samples per edge, we only have to test 4n samples per timestep.  If we sampled the entire volume we would have n2 tests per timestep.  An order of magnitude savings in sampling only the boundary.

Boundary Sampling

Volume Sampling

Penetration Depth

    A harder problem to solve in rigid body dynamics is determining penetration depth.  It is not practical to make timesteps infinitely small in a simulation to detect surface contact.  To correctly account for collisions that have gone too far the system must calculate the penetration depth and adjust the contact forces accordingly so that the rigid body is accurate displaced.  Volume sampling can provide the system with the penetration depth.  By knowing what samples are in contact, we know the exact position of the rigid body inside the object, which is once again limited by the sampling density.  At this point the system can calculate the new position of the rigid body with respect to the penetration.  A diagram of this concept is shown below.
 

Before Collision

After Collision

    The white object collides with a volume sampled rigid body.  The timestep advances the body too far causing penetration.  The red colored samples indicate the intersection of the two objects.  Knowing the sampling density of the rigid body, we can compute the penetration depth, and even the volume of the intersection.

Hardware Accelerated Sampling

    Another solution to the sampling problem suggested by Kenny Hoff is to use graphics hardware to compute the sampling for us.  Given the definition of an object and a resolution, the object can be rendered into the specified resolution using graphics hardware.  Then the pixels become the samples for the object.  Any object can easily be rendered and have the sampling computed at any resolution, this allows users to modify objects quickly without having to recompute coordinates for samples.  We have just found one more use for graphics hardware!

Arbitrary Object in Framebuffer

Pixels Represent Samples

ADD DISCUSSION OF USING STENCIL BUFFER OR ALPHA TO FIND COLLISION (see board)
 

    Now that we have a sampled rigid body and a collision, we need to compute the rebound forces and apply them to the rigid body.  In order to compute the rebound, we must know various values such as the incident angle of the particle and normal of the voronoi site it is colliding with.  Everything is known about the particle, such as position, velocity, etc.  Here I present two ways to compute the normal of the voronoi site.

    For simple objects such as lines and points, the normal can be geometrically computed.  The particle has the id of the voronoi site, at this time we know what the geometry of the site is.  If we have a point site, then the normal is direction of the vector from the point site to the particle.  This can easily be computed because we know the position of both the particle and the point site.  If the voronoi site is a line, then the two endpoints are known, the slope and normal can be calculated.  The problem is that we do not know which direction the normal is facing.  The depth buffer is positive on both sides of the voronoi site, so the site will actually detect collisions from both sides.  This provides problems because if a boundary sampled rigid body penetrates too far, it will appear on the other side of the voronoi site.  The particle could appear to be moving away from the voronoi site, and the collision will not be reported.  Since we are not striving for exact physics, I am calculating the normal arbitrarily and finding the relative velocity in the normal direction.  If the relative velocity is negative, this indicates that the rigid body velocity is in the opposite direction of the normal, which is correct.  If the relative velocity is positive, then we must flip the normal and continue.

vrel = n · (va - vb)

    Where n is the normal, va is the velocity of the particle and vb is the velocity of the voronoi site (zero).  At this point we can continue down two paths to compute the rebound.  The first path uses Baraff's notion of an impulse force which is accurate, the second path uses physics of light to compute the rebound which is fast and not exact.  For this project I will not be simulating contact (resting) forces, which is very difficult to do.

Impulse Based

    The notion of an impulse force is used to instantaneously apply a force to the rigid body to update the state according to the collision with the site.  To compute the impulse force we need to know the velocity of the particle, which is composed of its linear and angular velocity.

va = va + wa x (pa - xa)

    Where va is the linear velocity of the particle (same as rigid body), wa is the angular velocity, pa is the position of the particle in world space, and xa is the position of the center of mass in world space.  Let x denote the cross product.  From this we can compute a vector quantity J that is the impulse.  Applying the impulse will produce an instantaneous change in the velocity of the body.  Applying the impulse to a rigid body with mass M produces a change in velocity, linear momentum and torque.

vdelta = J/M
Pdelta = J
timpulse = (pa-xa) x J

    In a frictionless system the impulse acts in the same direction as the normal.  Using this and the above relations we can compute a scalar j and update the system accordingly.  This is shown in detail in Baraff's course notes and will not be shown here.

Physics Based

    A simpler way to compute the update the system is to use the physics.  Knowing the state of the particle, position, velocity, etc, and the normal to the voronoi site as shown before, we can simplify the problem and get a close approximate to the impulse based dynamics.  Lets first show the components of the velocity of a particle.  The rigid body as a whole moves with the same linear velocity.  The rigid body may also be rotating with an angular velocity.  The velocity of each sample has the same linear velocity as the center of mass, however the angular velocity is directly effected by the distance from the center.  Earlier we showed how to compute the total velocity.  Notice how the angular component is coupled with the distance between the sample and center of mass.  The composed instantaneous velocity is shown below.

Linear and Angular Velocities

Total Composite Vector

    Using some properties of physics, we know that in a perfect simulation, the angle of incidence is equal to the angle of reflectance.  The angle of incidence is simply the angle between the incoming velocity vector and the normal of the surface.

Reflected Vector

Reflected Linear and Angular Velocities

    First we must normalize the velocity vectors and compute the dot product with the normal to the site.  From this we can compute the reflected ray:

vref = ( n . ||v||) * n - vnorm

    The reflected ray must then be scaled back to its original magnitude.  By similar methods we can compute the instantaneous force used to repel the rigid body.  Torque can be computed by using the rebound force F:

tref = (pa-xa) x F

    In order to make the simulation look realistic, we must introduce scalar quantities that help the physics.  By playing with the scalars we can create the effect of friction that helps with the rotation and torque of the body.  The various scalars can be used to simulate different surface effects, and can be tailored for each voronoi site.  One site may be very slippery, while another can be rough causing a certain 'stickyness' to it so that the body will rotate much faster or dampen the rebound.  The overall effects of using this method for computing the collision forces is very good, and can save time over the impulse based method.

Sampling the Depth Buffer for the Normal

    So far we have talked about computing the normal of a line or point site.  What if we want to use arbitrarily shaped geometry such as bezier curves in our environment?  We already know how to compute the voronoi diagram for such a curve (not discussed here), the problem is how do we compute the normal?  A solution to this is to sample the distance in the depth buffer volumetrically.  By taking samples from the depth buffer that are one pixel away we can look at the local behavior of the bezier curve.  Given these local points we can approximate the normal to the surface.

All Samples on One Side

Sampling on Wrong Side

    Note that this method will work for line and point based voronoi diagrams, although it may not provide the exact answer which can be obtained geometrically from these sites.

An Alternate Way to Compute the Normal

    An alternative method to determining the normal of a voronoi site is to use a more geometric approach to the fixed site.  Instead of having a single line site as previously described, we can create a rectangle out of four voronoi sites.  These sites will have a closed interior which we can special case so that the colors are offset by a certain value, so that if a sample finds these colors it will know that it has penetrated through and correctly compute the normal.
 

Four Voronoi Line Sites

Altered Interiors

    The alternate colors on the interior of the block will allow the solver to detect penetration and correctly compute the normal.  This method can be used for any shape voronoi site.
 

    Rigid body simulation requires an ordinary differential equation (ODE) solver for motion.  There are many different methods used for accurately (or inaccurately) solving these equations.  The easiest method to update the motion of a system is to use Euler's method.  A more complex, and more accurate, method is the Runge-Kutta method.

    Euler's method for computing the motion is a 2nd order solver that approximates the next value by using the first derivative at the current value.  Given a timestep h that is used to increment the system and a position y at time ti, Euler's formula states:

yi+1 = yi + h*yi'

    Where yi' is the first derivative of the position function, velocity in our case.  The value of h directly determines the accuracy of Euler's method.  Keep in mind that h is normally 1/30 or 1/60 depending on how fast (or accurate) you want the simulation to be.  The error in approximation for Euler's method is

error ~ h2y''(ð)/2

    The Runge-Kutta (RK) method of approximation is a 4th order solver that uses a weighted predictor-corrector strategy to obtain the value at the next timestep.  RK's formula is a bit more complex the Euler's method:

yi+1 = yi + 1/6(a+2b+2c+d)
a = h*yic'
b = h*F((i+1/2)*h, yi + a/2)
c = h*F((i+1/2)*h, yi + b/2)
d = h*F((i+1)*h, yi + c)

error ~ ðh5

    As you can see RK's error is much smaller by a numerous orders of magnitude.  The difference in calculation between the two systems is noticeable, but for modern day computers should not be a limiting factor in the simulation.  There is also an adaptive RK strategy that will change the value of h appropriately for greater precision.

    When performing multipass rendering it is very important to speed up computation as much as possible.  When computing collision detected we need to read back the depth buffer.  Many people would read back the entire buffer, then index only what is needed.  This seems like a lot of wasted space.  One way to help get around this is to window what is needed to be read back, that is, create a boundary around the object that data is needed and read back only that data.  There are many implementation specific performance tips that should be utilized when doing pixel transfer operations.  For high end SGI machines such as the InfiniteReality2, pixel transfer is very fast for large volumes of data.  When reading back the depth buffer it is better to perform this operation a single time and receive all of the data you need.  When running on PC architecture, pixel transfer performs much better in small volumes, it is better to read back per pixel values at a time instead of a buffer's worth.
    Bounding boxes may be utilized to prune collision detected down to only when the rigid body is close to the object.  For example, if the rigid body is a box, we can image a bounding circle around the box.  At each timestep test the distance at the center of the box (center of mass), if the distance is greater then the radius of the bounding circle then we are not in danger of collision.  Only test the samples when the distance from the centroid is within the radius.  This speedup method is only useful for certain scenarios, because finding a tight fitting bounding circle around complex rigid bodies is not always efficient.  This method will also not work with the next tip either, which is an important one.
    Another way to speed up performance is to limit the size of the voronoi diagram.  Since we only care about the voronoi diagram when there is a collision, why should we need to draw it on the entire scene, we can just draw it to the tolerance distance used for collision.  This will dramatically speed up the first pass rendering of the voronoi diagram.  The images below show the full scene voronoi diagram on the left, and a shortened diagram on the right.  The image on the right is still oversized, it is shown this way for visualization purposes, think of the colors as being inside the collision distance tolerance.


The full Voronoi Diagram

The Smaller (More Efficient) Diagram
    The first problem with the system described is that it cannot handle multiple rigid bodies.  As we all know, almost every rigid body simulation uses multiple bodies.  This can be accomplished by making a small modification to the current method of computing collision detection.  Each rigid body will be required to have its own voronoi diagram computed and drawn.  The trick is that when rigid body 'A' is testing for its collisions with other bodies, it cannot have its voronoi diagram drawn on the scene, otherwise it is always closest to itself.  This leads us to an incremental approach for performing multiple body interaction.  Each rigid body must test its interactions separately, so when rigid body 'A' is testing for collisions, everything in the scene will need to be drawn except its own voronoi diagram.  This will needed to be done for each rigid body.  This could be done at each timestep, however in a rigid body simulation only one collision can occur at a timestep.  This could possibly be used to determine a scheduling strategy for collisions.

    The methods I have presented for sampling a rigid body are very general methods.  Another possible way to sample the objects is stochaistically.  A random sampling strategy make work very well for some cases.  Exploring this idea will be very useful, especially in 3D rigid body dynamics.

    We've done 2D rigid body dynamics and shown that the collision detection can be done with voronoi diagrams.  What everybody wants is 3D!  My focus this summer will be to explore how to use the voronoi diagram in 3D to perform collison detection in rigid body dynamics.  To perform collision detection we will be using 2D slices of the objects in 3D, should be interesting.  There is a lot of work to be done this summer, check back in the fall for a progress report.

    The goal of this project was to research the feasibility of using the hardware acclerated generalized voronoi diagram to do collision detection.  I have found that this is indeed possible and have shown it with a demonstration.  I have spent a great deal of time thinking of the myriad of possibilities that can branch from the research report above.  I have learned a great deal about many topics, including rigid body dynamics, multipass rendering, collision detection, volumetric and geometric sampling, and much more.  I am very excited to continue my work with the geometry group here at UNC-CH this summer.
 
home

346 Sitterson Hall, CB #3175, Chapel Hill, NC 27599-3175, andrewz@cs.unc.edu