Colision Response Problem

Started by
18 comments, last by Agemaniac 20 years, 9 months ago
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..
Advertisement
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]

Everything is better with Metal.

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.!!


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;
}

Everything is better with Metal.

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.
ow..forgot...what you mean by "and multiply the matrix by the mass as well"?? multiply the inv_body or the invw matriz? how?
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.
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).

Everything is better with Metal.

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.
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);
}

Everything is better with Metal.

This topic is closed to new replies.

Advertisement