Archived

This topic is now archived and is closed to further replies.

Agemaniac

Colision Response Problem

Recommended Posts

Hello..i''m working in a game and i have some problems with collision response. I already have the point of collision (i''m using Coldet to find it) and the objects that are colliding. how should i update the values of position, velocity, angular momentum etc, etc... I''m using the following piece of code, but it not seen to work. Can someone tell me what i''m doing wrong? cVETOR3D position = colision_point; cVETOR3D r1 = position - obj1.position; cVETOR3D r2 = position - obj2.position; //should i normalize position here??? //r1.Normalize(); //r2.Normalize(); cVETOR3D vel1= source1.velocity+ Cross (source1.velocidade_angular, r1); cVETOR3D vel2= source2.velocity+ Cross(source1.velocidade_angular, r2); float impulse_numerator1 = -(1.0f + obj1.restitution_coefic) * Dot(vel1, normal_colision); float impulse_numerator2 = -(1.0f + obj2.restitution_coefic) * Dot(vel1, normal_colision); float impulse_denominator1 = pac_colisao.obj1.OneOverMass + Dot(vcross_aux.Cross(source1.invw_inertia_tensor * Cross(r1, normal_colision), r1), normal_colision); float impulse_denominator2 = obj2.OneOverMass + Dot(Cross(obj2.invw_inertia_tensor * Cross(r2, normal_colision), r2), normal_colision); if (impulse_denominator1 == 0) impulse_denominator1 = 1; if (impulse_denominator2 == 0) impulse_denominator2 = 1; cVETOR3D impulse1 = normal_colision * (impulse_numerator1/impulse_denominator1) ; cVETOR3D impulse2 = normal_colision * (impulse_numerator2/impulse_denominator2); //apply impulse to primary quantities obj1.velocidade = impulse1 * obj1.OneOverMass; obj2.velocidade = impulse2 * obj2.OneOverMass; obj1.angular_momentum = Cross(r1, impulse1); obj2.angular_momentum = Cross(r2, impulse2); //compute affected auxiliary quantities obj1.angular_velocity = obj1.invw_inertia_tensor * obj1.angular_momentum; obj2.angular_velocity = obj2.invw_inertia_tensor * obj2.angular_momentum; if you know plz..post the correct form to calculate each of them when you already now the collision point

Share this post


Link to post
Share on other sites
Hi,

The r1,r2 are correct. You shouldn''t normalize them.

The problem is, there is only one impulse to be calculated. Minus of this impulse is applied to the other object.

>>float impulse_numerator1 = -(1.0f + obj1.restitution_coefic) * >>Dot(vel1, normal_colision);

You must calculate relative velocity instead of vel1. Let vrel=vel1-vel2

the expression must be (we have only one impulse numerator)
>>float impulse_numerator = -(1.0f + obj1.restitution_coefic) * >>Dot(vrel, normal_colision);

I didnot check the denominator side but actual denominator is
the total of the denomitors you used.

So

impulse= impulse_numerator / (impulse_denominator1+impulse_denominator2);
I am assuming you calculated the denominators correctly.



Share this post


Link to post
Share on other sites
hi.thanks for the post..
ok...here is my problem with what you said

>>float impulse_numerator1 = -(1.0f + obj1.restitution_coefic) * >>Dot(vel1, normal_colision);

You must calculate relative velocity instead of vel1. Let vrel=vel1-vel2

ok..with this code i dont need to calculate vel1 and vel2...note that its not obj1.vel1...its
cVETOR3D vel1= source1.velocity+ Cross (source1.velocidade_angular, r1);

is it really wrong??

Share this post


Link to post
Share on other sites
Hi,

I assumed that vel1 and vel2 are the velocities at the contact point not objects'' linear velocities.

vrel = v1+ w1 x r1 - ( v2 + w2 x r2 )
is the relative contact point velocity. ( v1 ,v2 are linear velocities and w1,w2 are angular velocities)

You can check Chris Hecker web page (http://www.d6.com/users/checker)
for more information.
Also from Brian Mirtich papers you can find collision responses with friction.

Share this post


Link to post
Share on other sites
Hello!! Now i figure out that i was using the incorrect formula.
now i''m trying to do the following thing found in the paper that you told me

impulse_numerator = -(1+e)vab . n

impulse_denominator = n . n(1/massA + 1/massB)
+ [(Ia(Rap x n))xRap + (Ib(Rbp x n)) x Rbp] . n;

obs: Ia and Ib = inverse world inertia tensor

I thougth impulse_numerator is right.
but looking to the impulse_denominator formula i can''t understand what is n . n (1/massA + 1/massB).
should i do n . n first? I don''t think so ..because dot product between them will be equal zero, then...should i do n . ( n(1/massA+1/massB)?
i try use this kind of thing but the impulse_denominator seen to have a too "big" value.

ok.other problem...
after calculate impulse, what can i do?
i''m using the following piece of code...

impulse = impulse_numerator/impulse_denominator * normal_collision
obj1.velocity += Cross(impulse, collision_normal);
obj2.velocity - = Cross(impulse, collision_normal);
.....

how can i know if i have to do this or:
obj1.velocity -= Cross(impulse, collision_normal);
obj2.velocity + = Cross(impulse, collision_normal);
.....

i know that i have to aply the impulse in one object and minus impulse in the other..but i don''t know in which aply each impulse....sorry ..my english is poor..hope that someone can help me....thanks.

Share this post


Link to post
Share on other sites
n.n is not equal to zero. It is equal to magnitude of n. If n is normalized ,it is one.

Did you understand the difference between dot product and cross product. They are wholly differnt.

Ok here is velocities after collision

obj1.velocity+=impulse*obj1.oneovermass
obj2.velocity-=impulse*obj2.oneovermass

obj1.angularvelocity+=obj1.invw_inertia_tensor * cross(r1,impulse)

obj2.angularvelocity-=obj2.invw_inertia_tensor * cross(r2,impulse)

Share this post


Link to post
Share on other sites
the same, innit?

(n.n)*k will get you there faster than n . (n * k)

only one dot product and a mul, instead of a vector mul and a dot product

and a small typo

"n.n is not equal to zero. It is equal to magnitude of n"

it''s actually the square magnitude of n.

magnitude(n) = sqrt(n.n)

Share this post


Link to post
Share on other sites
yep...now i found the correct formulas and everything looks fine...just one thing is incorrect(i thought)
when i use two spheres to test the algorithm i found out that it works well when i''m using colisions normals like (1,0,0)
(0,1,0), Normalize (1,1,1) and so on....when the colision normal change just a bit, (0.99954, 0.000332, 0.0099) the impulse seens to be wrong. The two spheres with initial velocities (20,20,20)
(-20, -20, -20) dont change velocities...the final velocities are like (18,18,18), (-17,-17,-17).."just an example...not real values"........i''m sure that the velocities when the impulse is aplied should change at last their signs...otherwise the spheres are going to collide forever.

does anyone know what is wrong?? i''m using coldet to find the colision normal..and since my spheres are made of triangles the collison normal can be like i said.

i''m using the following:



cVETOR3D position = colision_point;
cVETOR3D r1 = position - obj1.position;
cVETOR3D r2 = position - obj2.position;
cVETOR3D vel1= source1.velocity+ Cross (source1.velocidade_angular, r1);
cVETOR3D vel2= source2.velocity+ Cross(source1.velocidade_angular, r2);
cVETOR3D velr= vel1 - vel2;

float impulse_numerator = -(1.0f + obj1.restitution_coefic) * Dot(velr, normal_colision);

float impulse_numerator1 = -(1.0f + obj1.coeficiente_de_restituicao) * Dot(velr, normal_tri_1);

cVETOR3D impulse_denominator1 = vcross_aux.Cross(source1.invw_inertia_tensor * vcross_aux.Cross(r1, pac_colisao.normal_tri_1), r1);

cVETOR3D impulse_denominator2 = vcross_aux.Cross(source2.invw_inertia_tensor * vcross_aux.Cross(r2, pac_colisao.normal_tri_1), r2);

cVETOR3D impulse_denominator_parcial = impulse_denominator1 + impulse_denominator2;

float impulse_denominator_parcial2 = obj1.OneOverMass + obj2.OneOverMass + Dot(impulse_denominator_parcial, normal_tri_1);

cVETOR3D impulse = pac_colisao.normal_tri_1 * (impulse_numerator1/impulse_denominator_parcial2);

//apply impulse to primary quantities
obj1.velocity += impulse * obj1.OneOverMass;
obj2.velocity -= impulse * obj1.OneOverMass;
obj1.angular_momentum = Cross(r1, impulse);
obj2.angular_momentum = Cross(r2, impulse);

//compute affected auxiliary quantities
obj1.angular_velocity = obj1.invw_inertia_tensor * obj1.angular_momentum;

obj2.angular_velocity = obj2.invw_inertia_tensor * obj2.angular_momentum;




when i use it impulse_denominator_parcial2 seens to change like 0.2 to 2.0 when using normal colision (1,0,0) and (0.999, 0.0007, 0.0007)...(provided by coldet)...it changes a lot the impulse result and the velocity is not update properly...can someone figure out what is wrong???

Share this post


Link to post
Share on other sites
I don''t understand...

What''s normal_tri_1?

you only need to use normal_colision

and you had a ''='' instead of a ''+='' when computing the angular velocity.




cVETOR3D position = colision_point;
cVETOR3D r1 = position - obj1.position;
cVETOR3D r2 = position - obj2.position;
cVETOR3D vel1 = source1.velocity+ Cross(source1.velocidade_angular, r1);
cVETOR3D vel2 = source2.velocity+ Cross(source1.velocidade_angular, r2);
cVETOR3D velr = vel1 - vel2;

float impulse_numerator = -(1.0f + obj1.restitution_coefic) * Dot(velr, normal_colision);


cVETOR3D impulse_denominator1 = vcross_aux.Cross(source1.invw_inertia_tensor * vcross_aux.Cross(r1, normal_colision), r1);

cVETOR3D impulse_denominator2 = vcross_aux.Cross(source2.invw_inertia_tensor * vcross_aux.Cross(r2, normal_colision), r2);

cVETOR3D impulse_denominator_parcial = impulse_denominator1 + impulse_denominator2;

float impulse_denominator_parcial2 = obj1.OneOverMass + obj2.OneOverMass + Dot(impulse_denominator_parcial, normal_colision);

cVETOR3D impulse = normal_colision * (impulse_numerator1/impulse_denominator_parcial2);

//apply impulse to primary quantities
obj1.velocity += impulse * obj1.OneOverMass;
obj2.velocity -= impulse * obj1.OneOverMass;
obj1.angular_momentum = Cross(r1, impulse);
obj2.angular_momentum = Cross(r2, impulse);

//compute affected auxiliary quantities
obj1.angular_velocity += obj1.invw_inertia_tensor * obj1.angular_momentum;

obj2.angular_velocity += obj2.invw_inertia_tensor * obj2.angular_momentum;

Share this post


Link to post
Share on other sites
Ok...i''m using normal_tri_1 as a normal_collision..sorry...i''ve forget to put += in the angular velocity...but the impulse is wrong...yet.........a little change in the normal_collision cause to much change in the denominator..

Share this post


Link to post
Share on other sites
I don't see anything wrong with the algo, you must be doing something bad elsewhere. Have you tried with a moving ball and an infinite, static plane? Replace Obj2.OneOverMass by 0.0f in all equations, it should give an impulse

impulse = -(1+e) * va.n / [ (1/massA) + [Ia_inv * (Rap x n)xRap].n];

if that's still wrong, my guess is, you computed the inverse inertia matrix wrongly.

this is what I've got

m_RotVelocity, m_RotAcceleration, m_Position are vectors
Qs are quaternions
m_Orientation is a 3x3 matrix.



//-------------------------------------------------------

// Euler Integration

//-------------------------------------------------------

m_LinAcceleration = m_Forces * m_InvMass;
m_RotAcceleration = m_Torques * m_InvInertia;


//----------------------------------------------------------------------

// Poisot equation to integrate for orientation

//----------------------------------------------------------------------

Quaternion Qvel = Quaternion(m_RotVelocity, 0) * m_Q * 0.5f;
Quaternion Qaccel = Quaternion(m_RotAcceleration, 0) * m_Q * 0.5f;

m_Position += m_LinVelocity * m_dt + m_LinAcceleration * (m_dt*m_dt*0.5f);
m_Q += Qvel * m_dt + Qaccel * (m_dt*m_dt*0.5f); // standard euler equation, like for position


m_LinVelocity += m_LinAcceleration * m_dt;
m_RotVelocity += m_RotAcceleration * m_dt;

m_Q.Normalise();

//----------------------------------------------------------------------

// Convert quaternion to matrix

//----------------------------------------------------------------------

m_Orientation = m_Q;

//----------------------------------------------------------------------

// Calculate world cordinate inertia matrix

//----------------------------------------------------------------------

m_InvInertia = m_Orientation * m_InvBoxInertia * m_Orientation.Transpose();



[edited by - oliii on July 13, 2003 7:41:47 PM]

Share this post


Link to post
Share on other sites
Ok..i''m doing everything right..i guess...but i will put here some of the results..when i usei''m using real values now)
obj1.veloc = (-10,0,0)
obj1.position = (70,0,0)
obj2.veloc = (0,0,0)
obj2.position = (0,0,0)
obj1.OneOverMass = 0.1
obj2.OneOverMass = 0.1

when i use the algorithm and make the folowing lines before compute the impulse:

collision_normal.x = -1;
collision_normal.y = 0;
collision_normal.z = 0;

i got:

impulse_numerator = -20.000
impulse_denominator_parcial2 = 0.2
impulse = (100,0,0)
//aply impulse
obj1.veloc = (0,0,0)
obj2.veloc = (-10,0,0)

ok...here i thought everything is right..but my collision_normal is not (-1,0,0) because i''m using a sphere made by triangles..and coldet to return the collision normal..so it is like (-0.99047, 0.097549, 0.097549)
and i got:

impulse_numerator = -19.800
impulse_denominator_parcial2 = 1.8
impulse = (10.5,-1,-1)
//aply impulse
obj1.veloc = (-8.9,-0.1,-0.1
obj2.veloc = (-1,0.1,0.1)

and the problem is here..becouse the sphere one continue to hit the sphere two..i thought that a litle change in the normal like this should not make a diference in the impulse like that...it was because the impulse_denominator_parcial2 change a bit..and the impulse change a lot because of that.
i don''t know if it is normal or not..but it''s killing my brain.!!


Share this post


Link to post
Share on other sites
the results are not exactly surprising, for the first equation. it looks like the points of contact are directly aligned with the normal of collision, thuse making impulse_denominator1 and impulse_denominator2 = 0.

now, a small change in the normal would bring a large change in the denominator if the inverse inertia matrix is large, or if the points of contacts are set far from the centre of the sphere.


your inertia matrix should be something like


Matrix CCollSphere::CalculateInertiaMatrix(void) const
{
float i = m_Radius * m_Radius * 2.0f / 5.0f;

return Matrix (i, 0, 0,
0, i, 0,
0, 0, i);
}


and multiply the matrix by the mass as well.


and |r1| should be equal to obj1.radius and |r2| should be equal to obj2.radius.


what is vcross_aux anyway? can''t you get rid of it? just do

((r1 ^ collision_normal) * source1.invw_inertia_tensor) ^ (r1);

where

Vector3 Vector3::operator ^ (const Vector3& V) const
{
Vector3 Temp;
Temp.x = y*V.z - z*V.y;
Temp.y = z*V.x - x*V.z;
Temp.z = x*V.y - y*V.x;

return Temp;
}

Share this post


Link to post
Share on other sites
ok..now i''m initializing the invw_inertia_tensor with your function..but still have the same problem. I thought the denominator formula is wrong or something like that...i don''t now how to initialize the inverse_body_tensor matriz..so perhaps it can be the problem. (i don''t think). The invw_inertia_tensor is update by the following code :

target.invw_inertia_tensor = target.orientacao * target.invb_inertia_tensor * Transpose(target.orientacao);

i thought that it is right and i update the matriz every time that i will calc the impulse and update the velocities........i really don''t know what is going wrong.

Share this post


Link to post
Share on other sites
ah...your function
CalculateInertiaMatrix() calculate the "inverse" inertia body tensor?
ok...i will give some explanation about what i thought that is wrong with the denominator... in the calc of denominator1 and denominator2 there is the following code:

vcross_aux.Cross(r1, pac_colisao.normal_tri_1);
and
vcross_aux.Cross(r2, pac_colisao.normal_tri_1);

the result of the two lines diferes a lot of the result of the lines when using the normal (-1,0,0) and (-0.999, 0.1,0.1) with the same point of contact. then.. i thought that the inverse inertia is not the problem.........but i''m a newbie in this kind of code..perhaps i''m missing something.

Share this post


Link to post
Share on other sites
the problem with coliding perfect spheres, is that the cross products will always be 0, because the points of contact will always be aligned with the normal. So a small change in the normal will bring a large change in the cross product, if the spheres are large (r1 and r2 are large). That does not mean the result is invalid. However, cross products involving r1 and r2 should cancel each other out, as r1 will be close to -r2 (if the radius of the spheres are equal, and their mass are equal).

Share this post


Link to post
Share on other sites
can you explain what is inv_body_inertia_tensor? what does it mean? and what you mean by "and multiply the matrix by the mass as well"?? in your post.

Share this post


Link to post
Share on other sites
well, you''ve got a generic body inertia, that''s in model space. The inverse body inertia is just the inverse of the inertia matrix.

The calculations for body inertia is based on an object with a mass of 1 kg. To have the inertia, you have to scale it by the object''s mass.

the inertia matrix is only in object space. You need to convert it to world space to get the right impulses and force calculations.

world_inv_inertia = orientation * inv_local_inertia * orientation.transpose()

inv_local_inertia = local_inertia.inverse();

local_inertia = mass * sphere.CalculateInertiaTensor();

matrix CSphere::CalculateInertiaTensor()
{
int i = m_Radius * m_Radius * 2.0f / 5.0f;
return Matrix(i, 0, 0, 0, i, 0, 0, 0, i);
}

Share this post


Link to post
Share on other sites