top of page

Understanding 2D Physics Engines with Phaser 3, Part 23.2: Constrained Dynamics: Contact Constraint

  • cedarcantab
  • Jul 18, 2022
  • 4 min read

Updated: Aug 5, 2023

In the prior post started our exploration into the world of constraint solvers by looking at constraint functions.


In this post we will work through this with an example, the contact constraint or the non-penetration constraint.


Non-Penetration Constraint


Imagine two bodies, body 1 and body 2, moving with linear velocities v1/v2, and angular velocities ω1/ω2, that have collided (penetrated) at contact point p as follows.


ree


Position Constraint Function

We can express the contact point for body 1 and body 2 as follows:


ree



In the real world, there would be no "overlap" between two rigid bodies, hence there would be no separate p1 and p2. However, in physics simulations, bodies do overlap (penetrate each other) so that there is a "gap" between p1 and p2. This "gap" must be reduced to zero so that the bodies are not overlapping - this is resolving the non-penetration constraint.


The depth of penetration can then be expressed as:


ree



where δ would be positive if the bodies are separated and negative if the bodies are penetrating.


Hence, the position constraint function would be:


ree


Velocity Constraint function

We can perform the time derivative of the above to get the velocity contraint function.


ree

We can assume that the depth of penetration is small and ignore the second half of the equation, leaving us with:


ree


We want to isolate the velocity components from the above equation so that we can get the Jacobian. Things are a bit convoluted when working in 2D, as angular velocity is a scalar. If we consider the angular velocity as a 3d vector (since the scalar angular velocity can be considered as representing the magnitude of the angular velocity around the z-axis pointing out of the screen), we can use the following "hack" to change the cross product of ω and the radius r into the following matrix multiplication (remember, transpose of a skew-symmetric matrix is the negative of the original matrix and the cross product is ant-commutative, i.e. a x b = -(b x a)).

ree

(I have borrowed the big-R notation from Dyn4j)


and with the above, the velocity equation can be re-written as:


ree


Separating the velocity components gives you:


ree

Hence, by inspection the Jacobian matrix is:


ree


Calculating the Impulse Magnitude

Remember that we want to calculate:


ree



Relative velocity along the collision normal

Let's plug in the Jacobian for lambda, taking the first element of the numerator for starters.


ree

Similarly, plugging the Jacobian into the denominator part (effective mass) of the magic formula gives us:

ree

Effective Mass

Noting that the transpose of a matrix of matrices is the element wise transpose, and (AB)T = BTAT, plugging the Jacobian into the denominator part (effective mass) of the magic formula gives us:

ree

Moving from left to right the first two matrices we obtain:


ree

Working through the matrix multiplication again gives us:


ree

Since m is a scalar:


ree

and I is also scalar, the effective equation can be rearranged as:


ree

Breaking down the above into its elements, and looking at the third term in particular for easy analysis:


ree





Hence the effective mass in 2D is:


ree


Bias term


The bias velocity "vector" in constant constraints typically used for two things:

  1. correct the position error - Baumgarte Stabilization term

  2. to induce bounce - Restitution term


Baumgarte Stabilization

Applying impulse to "kill off" the relative velocity along the normal to zero is not enough. This will only prevent the two bodies from further penetrating. It does nothing to actually push them apart. For this you need to include something referred to as Baumgarte stabilization.


The basic idea is to feed the penetration depth (position error) back in as a bias velocity, or put another way, an extra bit of impulse is introduced into the system to push the two bodies apart. Such a bias velocity can be calculated as a multiple of the position constraint function error as follows.


ree


where, β is the bias factor.


C is from the position constraint function, ie the measure of separation. The constraint comes into action only when it is not satisfied, ie when the bodies are colliding. So C in the above term would be negative. Some implementations will use the depth of penetration instead of the "separation", and in such cases the sign will be different.

ree




Penetration Slop


The Baumgarte stabilization will try to correct the position constraint error even if the error is very small, even if the two bodies are penetrating by just a very small distance, an extra impulse will be applied. This can result in unnecessary "jitter". This can occur pretty much every frame if say a body is sitting on the ground and gravity is acting upon it.


This type of situation can be improved by allowing a bit of "leeway" in the penetration before actually applying Baumgarte stabilization - this is referred to as penetration slop.


ree

The penetration slop can be implemented as follows:

ree


The effect is to reduce the Baumgarte term to zero if it is less than the penetration slop.


Again, you need to be careful about how you are feeding in the error term. If the depth of penetration is used, the formula then becomes:

ree



Restitution term

Box2D-Lite does not deal with bounce. However, bounce can be achieved by adding another bias term. In this case we need to introduce some velocity reflection when a contact occurs.


If vn' is the relative velocity after contact we want the following relative velocity.


ree

where α is the restitution coefficient (if this is zero, there is no bounce).


This implies that:


ree


Hence, the restitution bias term is:


ree


There is a presentation by Erin Catto here which describes how it should be done.


Calculating the impulse and the Δv


Now we can calculate lamda, by calculating lambda we can calculate Δv to resolve the non-penetration constraint, ie the collision!

ree


Useful References










This actually has code in Javascript


Lots of useful stuff available here




 
 
 

Recent Posts

See All
p2 naive broadphase

var Broadphase = require('../collision/Broadphase'); module.exports = NaiveBroadphase; /** * Naive broadphase implementation. Does N^2...

 
 
 
p2 contact material

module.exports = Material; /** * Defines a physics material. To be used with {{#crossLink "ContactMaterial"}}{{/crossLink}}. * @class...

 
 
 

コメント


記事: Blog2_Post

Subscribe Form

Thanks for submitting!

  • Facebook
  • Twitter
  • LinkedIn

©2021 by Cozy Cozy World。Wix.com で作成されました。

bottom of page