3.6. RESTING CONTACTS AND FRICTION Exploration of resting contacts and friction Resolving a set of contacts Resting Forces A resting contact is a type of contact where the objects involved are moving neither apart nor together. In this case they need to be kept apart while making sure each object behaves normally using Newton’s Third Law of Motion: “For every action there is an equal and opposite reaction.” In other words, an object resting on the ground is subject to a gravitational force, pushing the object down, and an equal upwards reaction force from the ground preventing the object from moving down. Resting Forces Resting contacts could be handled by calculating the reaction forces and adding these into the overall mix of applied forces (using D’Alembert’s principle). This requires a global approach for contact resolution and becomes considerably more complex as the number of resting contacts between bodies increases. Whilst the above approach is more accurate (and adopted within industry strength packages) a less complex (and less accurate) solution can also be used: resting contacts are treated in terms of a series of micro-collisions. Micro-collisions Micro-collisions replace reaction forces by a series of impulses: one per update (i.e. the resting force is modelled as a series of impulses) Modelling a resting contact as a series of impulses may be problematic as, depending on the restitution, resolving the downwards motion may produce upwards motion - resulting in mini-bounces, i.e. jitter. This problem can be (mostly) overcome by: • • Removing any velocity built up from acceleration in the previous update. Decrease the coefficient of restitution for collisions with very low speeds. Micro-collisions: Removing Accelerative Velocity Removing velocity due to accelerative forces By tracking the acceleration at each rigid body update (only linear acceleration need be stored as most reaction forces arise from gravity – which is a linear acceleration), it becomes possible to calculate the desired change in velocity for a contact (Stage 4 of the Velocity Resolution algorithm) by subtracting the acceleration-induced velocity in the direction of the contact normal, vacc, ie. (where vs is the separating velocity and c is the coefficient of restitution): Micro-collisions: Lowering the Restitution A complementary approach to removing the effects of gravity acceleration is to also reduce the restitution of contacts involving very low closing velocities (thereby dampening all low speed contacts). This can be simply accomplished as: float appliedRestitution = contactVelocity.magnitude() < velocityLimit ? 0.0f : restitution; Introducing friction Types of Friction Friction is the force generated when one object moves or tries to move in contact with another. There are two forms of friction: static and dynamic. Types of Friction: Static Friction Static friction is a force that stops an object from moving when it is stationary and depends on the materials in contact and the reaction force: where fstatic is the friction force generated, μstatic is the coefficient of static friction (an empirical material-pair property) and r is the reaction force in the direction of the contact normal (given by where d is the contact normal and f is the total force exerted). As more force is exerted, static friction pushes back until the limit of static friction (μstatic|r|) is reached. A force beyond this limit may result in object movement, a sudden drop in the opposing frictional force, and the introduction of dynamic friction. Types of Friction: Dynamic Friction Dynamic (or kinetic) friction behaves like static friction but has a different coefficient of friction and can be defined as (where μdynamic is the coefficient of dynamic friction, and vplanar is movement velocity along the plane). Rather than acting in the opposite direction to the planar force (as for static friction), dynamic friction acts in the opposite direction to the object velocity (thereby acting to slow down and stop the object even if the applied moving force is removed). Within game physics, both types of friction are generally combined into a single model, with a single coefficient of friction. Types of Friction: Isotropic and Anisotropic Friction across a surface may be either isotropic or anisotropic. Isotropic friction has the same coefficient in all directions. Anisotropic friction can have different coefficients in different directions. Typically game engines are only concerned with modelling isotropic friction (or only support a simple anisotropic model of friction). Implementing Friction As an impulse-based approach using micro-collisions for resting contacts has been assumed, it will be necessary to implement friction within this framework (an approximation as resting forces are not calculated) Within a force based physics engine, friction would be introduced into the mix as another type of force. Friction as Impulses Given a contact, the velocity of the object is adjusted in the direction of the contact normal. By extending this approach to include the remaining two contact directions (i.e. representing directions in the plane of the contact) we have a means of introducing static and dynamic friction, i.e. the change in velocity now includes: Vector3 deltaVelocityVector( velocityChangeAlongCollisionNormal, contactVelocityAlongYAxis, contactVelocityAlongZAxis); Implementing Friction In order to calculate the maximum amount of planar velocity that can be removed (representing the limit of static friction) we use the relationship between velocity and impulse (where g is the impulse and m the mass): The normal reaction force can be approximately calculated from using the amount of velocity to be removed in the direction of the contact normal. Assuming Δv is the change in velocity the reaction force is approximated as: Hence, the maximum frictional impulse that should be applied is: Where Δgnormal is the impulse in the direction of the contact normal (i.e. the impulse which is currently calculated to resolve contact velocity) Implementing Friction Dynamic friction can be handled by scaling the y and z (i.e. planar) components of the impulse so that their combined size is exactly μ times the size of the x impulse: Vector3 impulseContact; Determine the impulse needed to remove all velocity components at the contact (including y and z planar velocities) – explored next. float planarImpulse = Math.Sqrt(impulseContact.y*impulseContact.y + impulseContact.z*impulseContact.z); Determine if the impulse to be applied falls within the range of static friction if (planarImpulse > impulseContact.x * friction) { Apply dynamic friction if needed impulseContact.y /= planarImpulse; impulseContact.y *= friction * impulseContact.x; impulseContact.z /= planarImpulse; impulseContact.z *= friction * impulseContact.x; } Modifying Velocity Resolution In order to introduce friction the following changes need to be made to the previous velocity resolution algorithm: Step 2: Determine the change in velocity (both linear and angular) at the contact point for each object per unit of applied impulse. Step 2 must now determine the change in velocity per unit impulse given any combination of impulses in the three contact directions. In order to do this, a matrix converting an input contact impulse vector into a corresponding velocity change vector must be built. Step 3: Invert the velocities determined in step 2 The inverse of the matrix produced in step two must be generated (i.e. thereby transforming a desired change in velocity into a corresponding impulse) Modifying the Velocity Resolution Algorithm Step 5. From the change in velocity we can calculate the impulse that must be generated. The inverted matrix must be used to determine the contact impulse vector. Additionally, the static/dynamic friction test (last slide) must be used to determine frictional planar velocity change. Determine (angular) velocity per unit of impulse Previously the following code was employed: Vector3 torquePerUnitImpulse = Cross( relativeContactPosition, contactNormal ) Vector3 rotationPerUnitImpulse = inverseInertiaTensor.Transform(torquePerUnitImpulse); Vector3 velocityPerUnitImpulse = Cross( rotationPerUnitImpulse, relativeContactPosition _); Vector3 velocityPerUnitImpulseContact = contactToWorld.TransformTranspose(velocityPerUnitImpulse); The above approach must be extended to use all three components of the basis matrix (and not just the contact normal). In order to take the (equivalent) cross product of the relative contact position and the contact basis matrix (which can be thought about in terms of turning an impulse into a torque), a skew-symmetric matrix is used. Determine (angular) velocity per unit of impulse Aside: Vector cross product is equivalent to multiplication by a corresponding skew-symmetric matrix, i.e.: Given a vector the vector product is equivalent to the following matrix-by-vector multiplication: Additionally, as we have Determine (angular) velocity per unit of impulse Hence: Matrix3 impulseToTorque Build a skew-symmetric matrix for the ‘cross’ product = BuildSkewSymmetric(relativeContactPosition); Determine the resultant torque per unit of applied impulse using the skew-symmetric matrix Matrix3 torquePerUnitImpulse = impulseToTorque * contactToWorld; Determine the resultant rotation per unit of applied impulse using matrix multiplication Matrix3 rotationPerUnitImpulse = inverseInertiaTensor * torquePerUnitImpulse; The inverse cross product is simply equivalent to a Matrix3 velocityPerUnitImpulse = 1 multiplication of the rotationPerUnitImpulse * impulseToTorque; skew-symmetric matrix velocityPerUnitImpulse *= -1; As before, the result is expressed in terms of contact coordinates Matrix3 velocityPerUnitImpulseContact = contactToWorld.Transpose() * velocityPerUnitImpulse; Determine (angular) velocity per unit of impulse The final matrix will transform an impulse in contact coordinates into a velocity in contact coordinates. If the contact is between two moveable rigid bodies, then the same process can be performed for each body and the results simply combined by using matrix addition to add both matrices together. Aside: See the recommend course text for an efficient means of accomplishing this. Determine (linear) velocity per unit of impulse As before, the change in velocity per unit impulse due to linear motion is found using: In order to transform this vector-to-vector transform into a matrix form that can be added to the angular matrix, the inverse mass is expressed in a matrix form, i.e.: multiplying a vector by a scalar quantity k is equivalent to transforming it by the matrix Hence, in order to combine linear and angular motion, the angular matrix need only be modified by adding the inverse mass to diagonal elements (e.g. matrix.M11 += inverseMass, etc.) A finished game physics engine With the above changes integrated, we have built an iterative, impulse-based, rigidbody game physics engine. The next section explores performance enhancements within the engine. Directed physics reading Directed reading • Read Chapter 15 of Game Physics Engine Development (pp351-374) on collision resolution with frictional forces. Summary Today we explored: How to resolve contacts taking into account frictional forces