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;
}
a
andb
). However, it is quite hard, so teleporting is not too bad. About the spinning : Ifa
is on the left and moving up, andb
is one the right and moving down, if they may join together, the overall result should roughly spin-as-one in clockwise direction. (I edited question a little, thanks.) – Fabulista+b
object instead. – Pecksniffiana+b
object. Origin is the center of mass of the objects combined and axises are aligned so the objects are in single line/axis (for example x) in each update apply rotations and movement to this reper and compute global position of the sub objects from it ... as their local coordinates would be always the same ... so its just matter of multiplying by direct or inverse matrix (depending on the notations used) – PecksniffianabsoluteTransformChild = absoluteTransformParent*relativeTransformOfThatChild
. (just in case if it is what you are explaining) ; Hmm, I still don't believe friction is related to this question. I agree that friction makes rotating ball move on a floor. – Fabulist