I have 2 rigid bodies (a
& b
) and 1 fix joint constraint (with relative transformation rela
).
My objectives are to achieve :-
No. 1. b.transform = a.transform * rela
No. 2. Center of mass (a
+b
) doesn't change.
No. 3. (3rd Newton rule) Velocity of total system (a
+b
) doesn't change.
No. 4. (3rd Newton rule) Angular velocity of total system (a
+b
) doesn't change.
No. 5. Moving/rotating of both objects to solve it should be minimized.
I wish to apply impulse/torque to both bodies to make them gradually meets the requirement.
This video can depict what I want - (youtube link).
How to solve the value of impulse/torque that apply for each body?
I want a rough idea / algorithm.
It can be a description text without any code.
Example
Here is a sample problem and its correct solution (i.e. final resting state) :-
Code (draft)
Here is my current snippet, just in case :-
class Transform {
Vec3 pos;
Matrix33 basis;
};
Each rigid body has these fields :-
class RigidBody {
float mass;
Matrix33 inertiaTensor;
Transform transform;
Vec3 velocity;
Vec3 angularVelocity;
};
The fix joint constraint is :-
class FixConstraint {
Transform rela;
RigidBody* a;
RigidBody* b;
};
Draft of my poor solution
In nutshell, I have to modify 12 variables.
- position of
a
andb
(xyz - 6 variables) - orientation of a and b (angle xyz - 6 variables)
Then I can use "My objectives" No 1 & 2 to create some equations.
Then, at best, I have to solve 12 linear equation with 12 unknown variables.
I doubt if it has to be that hard.
My previous internet search
I have looked into various sources, but they mostly :-
- just drive into iteration solver.
- try to diagonalize matrix + jacobian : only expert can understand.
- "Why don't you look into (insert name of Physic Engine here) source code?" without beginner-friendly explanation.
- show how to use (name of Physic Engine) to create a fix joint constraint.
Here are some of the most useful ones :-
- Bullet Physics solver : https://github.com/svn2github/bullet/blob/master/tags/bullet-1.5f/BulletDynamics/ConstraintSolver/Point2PointConstraint.cpp
- "Stable, Robust, and Versatile Multibody Dynamics Animation" research paper http://image.diku.dk/kenny/download/erleben.05.thesis.pdf (see chapter 6)
- (edited-add) Featherstone's algorithm for ragdoll : https://en.wikipedia.org/wiki/Featherstone%27s_algorithm (but it focuses on many constraints rather than one)
(edited some wording and rule, thank fafl and Nico Schertler.)
(edited-add, after a few days)
I believe if I can crack "Point2PointConstraint.cpp" (of the Bullet Physics), I will be fully understand the algorithm and principle.
I also copy-paste it here, just in case.
Here is the first part :-
SimdVector3 normal(0,0,0);
for (int i=0;i<3;i++)
{
normal[i] = 1;
new (&m_jac[i]) JacobianEntry(
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
m_rbA.getCenterOfMassTransform()*m_pivotInA - m_rbA.getCenterOfMassPosition(),
m_rbB.getCenterOfMassTransform()*m_pivotInB - m_rbB.getCenterOfMassPosition(),
normal,
m_rbA.getInvInertiaDiagLocal(),
m_rbA.getInvMass(),
m_rbB.getInvInertiaDiagLocal(),
m_rbB.getInvMass());
normal[i] = 0;
}
Here is the second part :-
SimdVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_pivotInA;
SimdVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_pivotInB;
SimdVector3 normal(0,0,0);
for (int i=0;i<3;i++)
{
normal[i] = 1;
SimdScalar jacDiagABInv = 1.f / m_jac[i].getDiagonal();
SimdVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
SimdVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
//this jacobian entry could be re-used for all iterations
SimdVector3 vel1 = m_rbA.getVelocityInLocalPoint(rel_pos1);
SimdVector3 vel2 = m_rbB.getVelocityInLocalPoint(rel_pos2);
SimdVector3 vel = vel1 - vel2;
SimdScalar rel_vel;
rel_vel = normal.dot(vel);
//positional error (zeroth order error)
SimdScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
SimdScalar impulse = depth*m_setting.m_tau/timeStep * jacDiagABInv - m_setting.m_damping * rel_vel * jacDiagABInv;
SimdVector3 impulse_vector = normal * impulse;
m_rbA.applyImpulse(impulse_vector, pivotAInW - m_rbA.getCenterOfMassPosition());
m_rbB.applyImpulse(-impulse_vector, pivotBInW - m_rbB.getCenterOfMassPosition());
normal[i] = 0;
}