Incorrect angular collision response

Started by
25 comments, last by Mailbox 5 years, 9 months ago
On 5/22/2018 at 12:44 PM, Mailbox said:

 

Oh, wait, you're only trying to calculate the collision response due to the linear impact WITHOUT taking into account friction... is that correct?  If so, my responses above were assuming you were trying to do both.   

Advertisement
1 minute ago, 0r0d said:

Oh, wait, you're only trying to calculate the collision response due to the linear impact WITHOUT taking into account friction... is that correct?  If so, my responses above were assuming you were trying to do both.   

Yes, I'm trying to get the basic collision response, without friction or restitution, working for now (although I have code for it already).

hmm you've tried a lot -- backing up one step - are you certain the inertia tensors are correct to start with?  How are they constructed?

 

43 minutes ago, Dave Roberts said:

hmm you've tried a lot -- backing up one step - are you certain the inertia tensors are correct to start with?  How are they constructed?

Well, I'm not certain whether the world space tensors are correct. However, I'm pretty sure the local ones are. Currently I have two boxes, both with the dimensions (X=0.5, Y=1.0, Z=1.5), mass 7.5 and inertia (X=2.03, Y=1.56, Z=0.78). The inertia is calculated using the equation for solid cuboids I found on Wikipedia. The inverse inertia tensor/matrix then has the values (M11=0.49, M22=0.63, M33=1.27), with the other components set to zero.

10 hours ago, Mailbox said:

I also tried to figure out how qu3e does it a few days ago, but it seems to do things a bit differently as far as I could see.

I wrote qu3e, so if you're confused on how something relates to your code snippet, you can just ask here :)

Thanks, tomorrow I'll definitely give it another try to understand what you're doing differently, hopefully getting closer to solve this mystery.

I don't understand why calculating the world space inverse inertia tensor with R*I*R^T doesn't work. It has the same effect as using only I. The only way I can get it to work is to transpose all my quaternion derived matrices, including the ones used for rendering, but then all rotations are negated. Otherwise I have to use R*I.

I've checked all functions involved in the calculation countless times. Maybe my coordinate system handedness is inconsistent, but I don't know where. My intention is to use a right-handed coordinate system, with x pointing to the right, y down and z away from the user. Matrices are row-major.

Some relevant functions:


Matrix3x3 Matrix3x3::Rotate(const Quaternion& quaternion)
{
	Matrix3x3 result;

	float xx = quaternion.X * quaternion.X;
	float yy = quaternion.Y * quaternion.Y;
	float zz = quaternion.Z * quaternion.Z;
	float xy = quaternion.X * quaternion.Y;
	float wz = quaternion.Z * quaternion.W;
	float xz = quaternion.Z * quaternion.X;
	float wy = quaternion.Y * quaternion.W;
	float yz = quaternion.Y * quaternion.Z;
	float wx = quaternion.X * quaternion.W;

	result.M11 = 1.f - 2.f * (yy + zz);
	result.M12 = 2.f * (xy + wz);
	result.M13 = 2.f * (xz - wy);

	result.M21 = 2.f * (xy - wz);
	result.M22 = 1.f - 2.f * (zz + xx);
	result.M23 = 2.f * (yz + wx);

	result.M31 = 2.f * (xz + wy);
	result.M32 = 2.f * (yz - wx);
	result.M33 = 1.f - 2.f * (yy + xx);

	return result;
}

Matrix3x3 Matrix3x3::Scale(const Vector3& v)
{
	return Matrix3x3(
		v.X, 0.f, 0.f,
		0.f, v.Y, 0.f,
		0.f, 0.f, v.Z);
}

Vector3 operator *(const Matrix3x3& m, const Vector3& v)
{
	return Vector3(
		Vector3::Dot(m.Row(0), v),
		Vector3::Dot(m.Row(1), v),
		Vector3::Dot(m.Row(2), v));
}

I also checked qu3e a bit more thoroughly than the first time, but couldn't find any relevant differences in the calculations. The ones I found didn't make a difference.

One thing that jumps out a bit is that your vector3 operator * overload is doing a post-multiply of a column  vector V.  However, your conversion of the quaternion to a rotation matrix is for pre-multiplying  row vectors.  

To construct a 3x3 rotation matrix suitable for use with a column vector convention you would do the following (Thanks wikipedia!)

Conversion to and from the matrix representation[edit]

From a quaternion to an orthogonal matrix[edit]

The orthogonal matrix corresponding to a rotation by the unit quaternion z = a + bi + cj + dk (with |z| = 1) when post-multiplying with a column vector is given by

image.png.9c314117296c47ff364935f0df4ee958.png

My math knowledge is quite lacking. I tried it with that formula, but it results in even weirder behaviour, including the X and Z axes being swapped.


result.M11 = q.X * q.X + q.Y * q.Y - q.Z * q.Z - q.W * q.W;
result.M12 = 2.f * q.Y * q.Z - 2.f * q.X * q.W;
result.M13 = 2.f * q.Y * q.W + 2.f * q.X * q.Z;

result.M21 = 2.f * q.Y * q.Z + 2.f * q.X * q.W;
result.M22 = q.X * q.X - q.Y * q.Y + q.Z * q.Z - q.W * q.W;
result.M23 = 2.f * q.Z * q.W - 2.f * q.X * q.Y;

result.M31 = 2.f * q.Y * q.W - 2.f * q.X * q.Z;
result.M32 = 2.f * q.Z * q.W + 2.f * q.X * q.Y;
result.M33 = q.X * q.X - q.Y * q.Y - q.Z * q.Z + q.W * q.W;

Wouldn't I simply have use the transpose with the code I posted earlier?

qu3e calculates the matrix the same way I do, but uses columns instead of rows in the dot product when multiplying with vectors. Bullet calculates the transpose, but multiplies with vectors the same way I do. Seems I mixed something up. Is the decision to use one or the other based on the handedness of the coordinate system, and/or something else?
Originally, I actually did multiply matrices with vectors the same way qu3e does it, but I tried out all kinds of things so my code is a huge mess now.

It is quite possible (i've seen it done on two projects) to get the notation wrong but get the matrix calcs correct and essentially cancel-out errors.  i.e. When you look at the math with the operator overloading you think columns, but under hood it is doing rows.  I'm not up much on my quaternion derivations, but i would guess the transpose is not correct because Matrix multiplies are not commutive.  

Being clear on if you are using column or row vectors as a  convention is super important though.

e.g. Break down some operations - if we have some object and then want to rotate object around y, move x+10

Row vectors:

VecNew = VecCurrent * Mat(Translate to origin) * Mat(rotate y) * Mat(Translate to old pos + 10 more x)

As a column vector, the operation Vec*Matrix is invalid  (3x1) * (3x3) is nonsense and we accumulate matricies on the left:

e.g.

VecNew = Mat(Translate to old pos + 10 more x) * Mat(rotate y) * Mat(Translate to origin) * VecCurrent

Sorry if this is not what you meant and obvious.

Keep us posted though - as I am really starting to wonder what the problem is.  

Suggestion:  Write a few hooks to use a debug, unit sized, impulse vector oriented on x,y or z and send it into your calcs at known hit locations for each object.  Ensure that this works for both cases where the normal may be inverted depending on the if it object 1 or 2.

??

DR

 

 

 

This topic is closed to new replies.

Advertisement