Please help me understand the correct way to treat inequality constraints in an NGS numerical scheme. Life is easy if we have only one such constraint: we just clamp the whole accumulated impulse in the velocity correction phase and just clamp every incremental impulse in the position coppection phase. A good exposition is e.g. Erin Catto, "Understanding Constraints", GDC2014, pp. 36-45. But it's more tricky if we want to solve more than one constraint simultaneously.
Let us consider for a certainty angular hinge constraints. There are three of them. Two of them are equality constraints assuring that bodies have a common axis. And one is an inequality constraint limiting their relative angle of rotation aroud that axis. Let us consider a situation where there's only one iteration, so there's no need to accumulate an impulse, for simplicity.
So what do we do? We compule lagrange multipliers corresponding to a reaction force: f = -effMass * Cdot, where f and Cdot are three-dimensional vectors ('cause there are three constraints). Then we clamp f3 (let the inequality constraint be the third) to make sure that it does not suck
. And here the subtlety comes: that clamping leads to necessity of correction of another impulse components: f1 and f2. Indeed, f is a solution to
Code: Select all
[ K11 K12 K13 ] (f1) (Cdot1)
[ K21 K22 K23 ] (f2) = - (Cdot2)
[ K31 K32 K33 ] (f3) (Cdot3)
If we changed f3 the first two equations are no longer hold true. We does not care about the third because we are already know the correct value of f3 (let us denote that new value f3'). So we need to find new f1' and f2' to make the first two equations hold true for a given f3':
Code: Select all
[ K11 K12 K13 ] (f1') (Cdot1)
[ K21 K22 K23 ] (f2') = - (Cdot2)
You can look at the implementation of PrismaticJoint in Box2D to see that idea in practice (SolveVelocityConstraints function). And here comes the question: there is such correction of fs in the velocity correction phase but there's not in the position correction phase (SolvePositionConstraints function). There's just fs in my notation, no f's calculation. Why?
I don't see any reasonable reason. We don't accumulate impulse when correct positions? So what? That correction is needed in that case too. Optimization of the price of a bit accuracy? It's tiny compared to the effective mass matrix computation.
Finaly, a bit more clearly, and less Box2D-related: whether position corrections should be managed the same way as velocities corrections (recompute "equalitiy impulses" f1 and f2 after clamping "inequality impulse" f3)? I'm quite sure they should be treated the same way, but Box2D code made me question it.