3.5. C ONTACT R ESOLUTION Resolving a set of contacts
Impulsive Torque
Given a set of contacts, it is the role of the contact resolver to apply the contacts to the associated rigid bodies, separating bodies which are interpenetrating and modifying linear and angular velocities based on the applied impulses.
From D’Alembert’s principle, a force acting on an object will generate both linear and angular acceleration. In the same way, a collision between objects (providing an ‘instantaneous’ force, i.e.an impulse) will provide both linear and angular velocity change. An instantaneous angular change is known as an impulsive torque, defined as Where u is the impulsive torque, I is the inertia tensor, and the angular velocity (c.f. for torque). Hence the change in angular velocity for an applied impulsive torque is given as: Reminder: When two objects collide they will bounce apart at a velocity that is a fixed multiple of their closing velocity immediately before the impact. Due to the speed of the bounce it is modelled as an instantaneous change of velocity, known as an impulse.
In the same way that an applied force will generate torque given (where q is the contact point, p the origin of the object, and f the applied force): The impulsive torque generated from the application of an impulse is given by:
Following a collision the separating velocity is related to the incident velocity as (where c is the coefficient of restitution): Depending on the characteristics of the objects involved, and the direction of the contact normal, this separation velocity will be made up of a different degree of linear and rotational motion. Light weight object, with a collision normal nearly directly through the centre of mass. Little impulsive torque generated. Heavier object with small moment of inertia about axis and off centre collision. Large generated impulsive torque, to the extent where most of the velocity change is angular, i.e. the linear motion will probably be downwards (with no bounce). Similar to 2nd example, but with much larger moment of inertia, i.e. a smaller impulsive torque is generated and there is less angular velocity change and greater linear velocity change.
Determining velocity following a collision
To resolve the relative motion of two moveable objects a total of four impulses need to be calculated: the linear and angular impulses for each object (if an object collides with an immovable object, then only the impulses for the moveable object need be calculated). The first three steps determine how an object will respond to an applied impulse in terms of linear/ angular velocity change. The last three steps determine what the applied impulse should be The six step process is as follows: 1. Build a world-to-contact transform matrix. All operations will be performed in local contact space. 2. Determine the change in velocity (both linear and angular) at the contact point for each object per unit of applied impulse. 3. Invert the velocities determined in step 2 to provide a means of finding the necessary impulse to generate a given velocity change (linear and angular) for each object.
4. Determine the desired change in velocity for each object (using object’s physical properties, contact closing velocity, etc.). 5. Calculate the impulse that must be applied (using step 3) to provide the calculated change in velocity (step 4) 6. Split the impulse into its linear and angular components and apply to each object.
For collision resolution only the separating velocity of the contact point is of interest (i.e. the maths is most expressed relative to the contact. The contact point can be considered the origin and the contact normal as one axis, around which two other axes can be selected to form an orthonormal basis. Hence, we will have to deal with world space, local object space and contact space. Building the contact coordinate axes Whilst one axis is already known (contact normal – say, the X axis) the other two axes must be arbitrarily selected (assuming isotropic friction or frictionless surfaces). This can be done making an initial guess for the remaining axes and altering if need be. See the recommended course text for details of this process.
Reminder: The inverse of a rotation matrix is the same as its transpose (although a matrix transpose is much more quickly calculated than an inverse). This is of use when converting from contact coordinates into world coordinates (i.e. using the inverse of the calculated basis matrix, which has been built as a rotational vector).
For a frictionless contact (as considered here) any generated impulse will only be applied along the contact normal. The velocity change per unit impulse has two components (linear and angular) which can be determined separately and then combined. For a body-to-body contact, the linear and angular changes for each body will be needed. The Linear Component The linear change in velocity for a unit impulse is in the direction of the impulse and is dependent upon the inverse mass (or the sum for two bodies)
The Angular Component 1. The amount of impulsive torque generated from a unit of impulse (q – contact point, p – body origin, d impulse direction, i.e. along contact normal): 2. The change in angular velocity for an unit of impulsive torque: 3. The velocity of a point due to an angular velocity (i.e. due to its position relative to the origin of the object and the object’s angular velocity):
Converting the following three equations into code we have the velocity caused by rotation per unit impulse. Vector3 torquePerUnitImpulse = Cross( relativeContactPosition, contactNormal ) Vector3 rotationPerUnitImpulse = inverseInertiaTensor.Transform(torquePerUnitImpulse); Vector3 velocityPerUnitImpulse = Cross( rotationPerUnitImpulse, relativeContactPosition _); Vector3 velocityPerUnitImpulseContact = contactToWorld.TransformTranspose(velocityPerUnitImpulse); float angularComponent = velocityPerUnitImpulseContact.x; The above provides a velocity in world space, which needs to be expressed in terms of velocity change along the contact normal (assuming the contact normal is along the x axis of the contact basis axes)
The final velocity change per unit of impulse is obtained by adding together the linear and angular values. Reminder: For contacts with two objects involved we have four values: the velocity caused by linear motion and by angular motion for each object.
For frictionless collisions this step is trivial. If d is the velocity change per unit impulse, then the impulse needed to achieve a given velocity change, g, is (where v is the desired velocity change):
In order to accomplish this it is firstly necessary to determine the closing velocity at the contact point. Using this the required change in velocity following the collision can be determined.
Calculating the Closing Velocity The total closing velocity is determined by the linear velocity and the linear velocity of the contact point due to rotation alone, i.e.: Vector3 velocity = Cross( body.Rotation, relativeContactPosition ); velocity += body.Velocity; Aside: The velocity components that are not in the direction of the contact normal represent how fast the objects are sliding past one another. This will be important when considering friction later. If the contact involves two movable bodies, then the second body’s values are added to the velocity vector to form the total closing velocity (in world coordinates). The velocity is then expressed in terms of contact coordinates (using the same process as before).
Calculating the Desired Velocity Change The desired velocity change at the contact is such that the existing closing velocity is removed and the final velocity is in the opposite direction to the closing velocity with a magnitude dependent on the input speed as modified by the coefficient of restitution, i.e.: float desiredDeltaVelocity = -contactVelocity.x * (1 + restitution); Note: Assuming the contact normal is along the x axis of the contact basis axes
Because friction is not being yet considered, only the impulse in the direction of the contact need be considered, which can be simply calculated as: Expressed in terms of world space (which makes applying the impulse more straightforward) this becomes: impulseContact.x = desiredDeltaVelocity / velocityPerUnitImpulse; impulseContact.y = 0; impulseContact.z = 0; Vector3 impulse = contactToWorld.transform(impulseContact);
To apply the impulse the following two equations are used (for linear and angular velocity change following an impulse): where the impulsive torque, u, is given by: Vector3 velocityChange = impulse * body[0].InverseMass; Vector3 impulsiveTorque = Cross(impulse,relativeContactPosition); Vector3 rotationChange = inverseInertiaTensor.Transform(impulsiveTorque);
The above will work for the first object in a collision but not for a second object (should one exist). Recall that both objects involved in the collision will receive a same sized impulse but in opposite directions. Additionally, recall that the contact normal is, by convention, from the first body’s point of view. Hence, in order to apply the impulse to the second body we simply need to change the sign of the impulse (using the same code setup as before). Once the linear and angular velocity changes have been determined, then they can be used to directly update the velocity and rotation of the collision object(s). body.Velocity += velocityChange; body.Rotation += rotationChange;
Separating objects following a collision
Interpenetrating objects following a collision need to be separated to ensure that objects appear solid within the simulation. Different approaches to interpenetration resolution include the following (non-exhaustive) options: Linear Projection The position of each object is moved apart from the direction of the contact normal so that the objects are not touching. For collisions involving two objects the amount each one moves is proportional to its inverse mass. PenetrationLinear Projection Whilst simple, this approach is not realistic as it does not take into account interpenetration arising from the rotation of the object.
Non-Linear Projection Both objects are moved in the direction of the contact normal until they are no longer interpenetrating. The movement takes into account both linear and angular velocities. The balance between linear and angular velocity depends on the inverse inertia tensor of each object. An object with a high moment of inertia at the contact point will rotate less and take more of its motion as linear motion. The opposite is true of an object that can rotate easily. The result does not realistically model reality; however, it appears mostly believable. Penetration Realistic (rotation and linear movement) Aside: The following will assume that non- linear projection will be used to resolve interpenetration.
The goal is to find the proportion of linear and angular motion for each object needed to separate them by the penetration depth. The amount of each depends on the inverse mass and the inverse inertia tensor of each object. To do this we can use the same physics approach as used to resolve collision velocity, i.e. modelling how the objects would be pushed apart by a deformation force.
Calculating the linear and angular movement components The inertia of each object (ie. its ‘resistance’ to being moved) is determined in the direction of the contact normal. The inertia will have both a linear and angular component. The linear component of inertia is, as before, simply the inverse mass. The angular component is calculated using the same sequence of operations as used previously. Determining the above for each object involved in the collision will determine the proportion of the penetration to be resolved by each component of each rigid body. Removing the interpenetrating using linear motion The linear motion portion of interpenetration can be easily corrected as: Body.Position += contactNormal * linearMoveAmount;
Removing the interpenetrating using angular movement Accounting for angular movement is more complex and requires the following steps: 1. Calculate the rotation needed to move the contact point by one unit Vector3 inverseInertiaTensor; body.GetInverseInertiaTensorWorld(inverseInertiaTensor); Vector3 impulsiveTorque = Cross( relativeContactPosition, contactNormal; Vector3 impulsePerMove = inverseInertiaTensor.transform(impulsiveTorque); Vector3 rotationPerMove = impulsePerMove / angularInertia; Determine the change in rotation for a unit impulse Divide by the angular inertia to find the rotation needed to get one unit of movement along the contact normal
2. Multiple this by the required rotation needed to remove interpenetration. This is simply determined as 3. Apply the rotation to the orientation quaternion. As explored before using: Vector3 rotation = rotationPerMove * angularMove
Avoiding Excessive Rotations There are two potential problems associated with the outlined non-linear projection approach: 1. If the moment of inertia of the object is small but its mass is large, then most of the extraction will be assigned to angular movement. Depending on the depth of penetration it may not be possible to separate the objects. 2. For large (or indeed modest) rotations there is a possibility that another part of the object will end up interpenetrating. Angular motion cannot separation objects Centre ● ● ● ● Rotation will cause opposite corner to interpenetrate The solution to both problems is to (arbitrarily) limit the amount of rotation that can be part of the penetration resolution.
Putting velocity and interpenetration resolution together
As noted, the collision detector will generate a number of pairs of contacts which will need to be resolved. The approach outlined here assumes each contact is separately resolved (using the method of resolving velocity and interpenetration as outlined above). In particular, collisions will be handled in order of severity (i.e. those with a large closing velocity or deep interpenetration). Aside: As noted, commercial physics systems tend to simultaneously solve groups of contacts which, whilst more complex, products more physically realistic behaviour.
Add forces and torques Determine position and velocities Build points of contact between bodies Write post collision position and velocities Contact information
The order in which contacts are resolved is significant as resolving one contact can push another into (greater) interpenetration. A good approach is to resolve contacts in penetration order. At each iteration the contact with greatest penetration is selected and resolved. The process is repeated until all contacts have been separated (or a maximum number of iterations have been reached). Iteration 1: Resolve Left Iteration 2: Resolve Right Iteration 3: Resolve Left Iteration 4: Resolve Right
The contact with the greatest penetration can be found by iterating over the contact list. Resolving the contact of greatest penetration will likely change the penetration of other contacts, i.e. it is necessary to update other contacts, e.g.: Strictly, UpdatePenetrations would require that the collision detection process be re-executed to provide fully accurate results (i.e. discovering new points which were not previously in contact), however, this is not computationally feasible within a game. for (int i = 0; i < positionIterations; i++) { // Find contact with greatest penetration... if (!worstContact) break; worstContact.ApplyPositionChange(); UpdatePenetrations(); }
An acceptable comprise is to do the following: 1. Whenever a contact is resolved, cache the linear and angular movement correction applied to the bodies (or body) associated with the contact. 2. Iteration over all other contacts. 3. If the other contact is associated with any of the resolved bodies (or body) then update that contact using the cached linear and angular movements. The penetration value is adjusted based on the movement difference between the current point and that following application of the applied linear and angular movements (as measured along the contact normal). Vector3 delta = Cross(rotationChange,relativeContactPosition) + velocityChange; Contact.Penetration -= rotationAmount * Dot( delta, contact.Normal)
The presented algorithm is similar to that for resolving interpenetration, i.e. at each iteration the collision with the largest closing velocity is selected and resolved. Iterations continue until all contacts are non-closing or a max iteration limit is hit. Reminder: The approach adopted here works well, but it is towards the more simple end of the spectrum of possible approaches. Vector3 delta = Cross(rotationChange,relativeContactPosition) + velocityChange; contact.Velocity += contactToWorld.TransformTranspos(delta); As before, changing one contact will also modify the closing velocities of other linked contacts. This can be done as:
Directed physics reading Directed reading
Directed reading Read Chapter 14 of Game Physics Engine Development (pp ) on collision resolution (without frictional forces).
To do: Read the directed reading. Consider if you might wish to develop your own physics engine as your project. Today we explored: How to resolve contacts (without worrying about frictional forces)