3.5.CONTACT RESOLUTION Resolving a set of contacts Impulsive Torque Contact Resolution 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. Impulsive Torques 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 velocity (c.f. for torque). Hence the change in angular velocity for an applied impulsive torque is given as: the angular Impulsive Torques 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: Rotating Collisions 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 Resolving Collision Velocity 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 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. Resolving a Contact 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. Build a world-to-contact transform matrix 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. Build a world-to-contact transform matrix 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). Determine velocity change per unit of impulse 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) Determine velocity change per unit of impulse 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): Determine velocity change per unit of impulse 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 _); 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) Vector3 velocityPerUnitImpulseContact = contactToWorld.TransformTranspose(velocityPerUnitImpulse); float angularComponent = velocityPerUnitImpulseContact.x; Determine velocity change per unit of impulse The final velocity change per unit of impulse is obtained by adding together the linear and angular values. Determine impulse for velocity change 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): Determine desired change in velocity 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. Determine desired change in velocity 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; 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). Determine desired change in velocity 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.: Note: Assuming the contact normal is along the x axis of the contact basis axes float desiredDeltaVelocity = -contactVelocity.x * (1 + restitution); Calculating the impulse to be applied 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: impulseContact.x = desiredDeltaVelocity / velocityPerUnitImpulse; impulseContact.y = 0; impulseContact.z = 0; Expressed in terms of world space (which makes applying the impulse more straightforward) this becomes: Vector3 impulse = contactToWorld.transform(impulseContact); Applying the impulse 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); Applying the impulse 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 Resolving Interpenetration 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. Whilst simple, this approach is not realistic as it does not take into account interpenetration arising from the rotation of the object. Penetration Linear Projection Resolving Interpenetration 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) Implementing Non-linear Projection 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. Implementing Non-linear Projection 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; Implementing Non-linear Projection 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 Determine the change in rotation for a unit impulse Vector3 inverseInertiaTensor; body.GetInverseInertiaTensorWorld(inverseInertiaTensor); Vector3 impulsiveTorque = Cross( relativeContactPosition, contactNormal; Vector3 impulsePerMove = inverseInertiaTensor.transform(impulsiveTorque); Divide by the angular inertia to find the Vector3 rotationPerMove = rotation needed to get one unit of impulsePerMove / angularInertia; movement along the contact normal Implementing Non-linear Projection 2. Multiple this by the required rotation needed to remove interpenetration. This is simply determined as Vector3 rotation = rotationPerMove * angularMove 3. Apply the rotation to the orientation quaternion. As explored before using: Implementing Non-linear Projection 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. The solution to both problems is to (arbitrarily) limit the amount of rotation that can be part of the penetration resolution. ● Centre ● ● ● Angular motion cannot separation objects Rotation will cause opposite corner to interpenetrate Putting velocity and interpenetration resolution together Collision Resolution Process 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). Collision Resolution Process Contact information Resolving Interpenetration: Resolve Order 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 Resolving Interpenetration: Implementation 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.: for (int i = 0; i < positionIterations; i++) { // Find contact with greatest penetration... if (!worstContact) break; worstContact.ApplyPositionChange(); UpdatePenetrations(); } 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. Resolving Interpenetration: Implementation 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) Resolving Velocity 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. As before, changing one contact will also modify the closing velocities of other linked contacts. This can be done as: Vector3 delta = Cross(rotationChange,relativeContactPosition) + velocityChange; contact.Velocity += contactToWorld.TransformTranspos(delta); Directed physics reading Directed reading • Read Chapter 14 of Game Physics Engine Development (pp301-349) on collision resolution (without frictional forces). Summary Today we explored: How to resolve contacts (without worrying about frictional forces)