I try to make a very simple 2d physic functions to solve rigidBody with with sphere particles as colliders,
I have so a rigidBody and particle class :
function _rigidBody () {
this._position = cc.p(0.0, 0.0);
this._angle = 0;
this._linearVelocity = cc.p(0.0, 0.0);
this._angularVelocity = 0.0;
this._force = cc.p(0.0, 0.0);
this._angularMoment = 0;
this._mass = 1.0;
this._particles = [];
}
function _particle () {
this._initialPosition = cc.p(0.0, 0.0);
this._relativePosition = cc.p(0.0, 0.0);
this._worldPosition = cc.p(0.0, 0.0);
this._linearVelocity = cc.p(0.0, 0.0);
this._force = cc.p(0.0, 0.0);
this._radius = 10.0;
}
and so basically, each frame I compute the new position of each particles store in each rigidBody, then I check for particle to particle collision and in case of collision, I compute a force to repulse them (base on radius and how munch there are inside them), then I store this force in the particle,
And I compute the LinearVelocity and AngularVelocity by adding and impulse to my rigidBody for all the force store on all particle it contain.
my function addImpulse (with impulse the force store in particle and position the world pos of my particle) :
this.AddImpulse = function(bodyIdx,impulse,position){
var b = g_Bodies[ bodyIdx ];
if(position == null){position = b._position;}
b._linearVelocity.x += (impulse.x/ b._mass);
b._linearVelocity.y += (impulse.y/ b._mass);
b._angularVelocity += ((position.x - b._position.x) * impulse.y -
(position.y - b._position.y) * impulse.x);
};
My problems is, this function works pretty fine for linearVelocity by for the angular velocity it seam to get really big at the most little collision, for now, I don't use any damping (linear or angular), and I don't have inertia for my angularVelocity,
I guess the miss of inertia is my problem, but I get a little confuse when I look in internet how to compute it,
I look in box2d to see were the inertia is store and it seams to be a variable of rigidBody (as mass).
I find in internet that the Inertia = mass * (r*r)
problem => what is r ...
-if is the distance for my gravity center (so the position of my rigidBody), is obviously equal to 0 all the time (body.position - body.position == 0 )
in box2d I found : this.m_I = massData.I - this.m_mass * (massData.center.x * massData.center.x + massData.center.y * massData.center.y); And massData.center seam to be the center of the shape from the rigidBody, problem in my case my shape is 2 sphere one at (0,10) and one at (0,-10), so the center of that is (0,0) ....
in an other website I found that : for(i < numberOfParticle) I += ( massOfParticle(i) * ( RelativePosOfParticle(i)*RelativePosOfParticle(i) ) In this case is better, because as I square the distance of each particle (instead of searching the center first), my I will be greater than 0. But so I'm not sure is the correct formula to use ...
If someone can explain me in a simple way, how to compute a Inertia ? If I can compute the inertia for my rigidBody directly (and not by particle) ? if I can store the inertia or if it deepens of where is apply the impulse (I read that also in an other website...) ? and/or why can I do wrong in my function of impulse to get a such big angular velocity (maybe is normal and the damping solve this problems is the others physic engine).
And also if someone could answer (just by curiosity), does box2d use a simple version of the inertia because is quicker to compute and the result are good enough ? Or does the calculation of Box2d is correct, and I miss something when I read the code ?
Thanks a lot ^^,
Marius.
First: you are correct, the problem is that you do not consider the moment of inertia (which is the rotational analog of mass). Look at the code:
b._linearVelocity.x += (impulse.x/ b._mass);
b._linearVelocity.y += (impulse.y/ b._mass);
b._angularVelocity += ((position.x - b._position.x) * impulse.y -
(position.y - b._position.y) * impulse.x);
When you calculate linear velocity, you divide by mass; you should do something similar for angular motion.
If the position of the rigidBody
is its center of gravity, then the job will be easy.
The moment of inertia is mr2, summed over the particles. That is, each particle contributes m*r*r
, where m
is the mass of the particle, and r
is the distance from the particle to the center of gravity.
For example, if your shape is 2 spheres, one at (0,10) and one at (0,-10), both of mass 5, then the center of gravity is at
C = (5*(0,10)+5*(0,-10))/(5+5) = (0,0)
and the moment of inertia is
I = 5*10*10 + 5*(-10)*(-10) = 1000
The change in angular velocity will be
b._angularVelocity += (((position.x - b._position.x) * impulse.y -
(position.y - b._position.y) * impulse.x))/I;
If your shape is 2 spheres, one at (0,10) with mass 5, and one at (0,-10) with mass 10, then the center of gravity is at
C = (5*(0,10)+10*(0,-10))/(5+10) = (0,-10/3)
and the moment of inertia is
I = 5*(40/3)*(40/3) + 5*(-20/3)*(-20/3) = 10000/9
EDIT:
A problem appears in the special case of a single sphere (or collocated spheres). These spheres are treated as point masses, so the moment of inertia (I
) will be zero. And all impulses are directed through the center of a sphere, so the torque (the angular "force") will be zero. So there should be no angular velocity, but by the method above it will be 0/0
. One solution: each sphere makes a small constant contribution to the inertial moment (this means that the sphere is not a point mass-- it has a slight extent, so it can spin). Now the contribution of each sphere is m*r*r + d
, where d
is, e.g. 0.0001
. So the lone sphere has a positive moment of inertia (and will not rotate), and all of the other objects still have realistic physics.