Resolving Interpenetration

advertisement
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)
Download