matrix normalization??
hi!
once again a matrix problem
i am multiplying lots of rotation matrices, and after a
while my rotations dont look as i think they should!
i once read somewhere, matrices should be normalized every
once in a while when multiplying them with each other ...
is that true? and could that be the reason for my problems?
and, if i have to do that, does anyone have a link
on HOW to normalize a 4x4 matrix??

sebastian
once again a matrix problem

i am multiplying lots of rotation matrices, and after a
while my rotations dont look as i think they should!
i once read somewhere, matrices should be normalized every
once in a while when multiplying them with each other ...
is that true? and could that be the reason for my problems?
and, if i have to do that, does anyone have a link
on HOW to normalize a 4x4 matrix??

sebastian
Floating point numbers are not 100% accurate (more like 99.99999999%); your matrix is indeed slowly diverging from the correct value. "Normalizing the matrix" means clearing it to the identity matrix and setting it explicitly to the rotation you want, instead of multiplying a rotation matrix with very small numbers a hundred thousand times.
What Mark says is true. If for instance you have an tumbling asteroid - you dont want to keep a matrix for the asteroid and just keep multiplying that matrix by some rotation matrix every frame to let all the rotations accumulate - because the asteroids matrix will start to skew due to floating point roundoff. You want to build the rotation matrix fresh each frame.
However I dont believe...
I use the math library called FreeMagic - which you can get at <http://www.magic-software.com> and it has this method for dealing with 3x3 matricies (and you really only need to apply this to the 'rotational' 3x3 section of OpenGL's 4x4 matrix)
[SOURCECODE]void Matrix3::Orthonormalize ()
{
// Algorithm uses Gram-Schmidt orthogonalization. If 'this' matrix is
// M = [m0|m1|m2], then orthonormal output matrix is Q = [q0|q1|q2],
//
// q0 = m0/|m0|
// q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0|
// q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1|
//
// where |V| indicates length of vector V and A*B indicates dot
// product of vectors A and B.
// compute q0
Real fInvLength = Math::InvSqrt(m_aafEntry[0][0]*m_aafEntry[0][0]
+ m_aafEntry[1][0]*m_aafEntry[1][0] +
m_aafEntry[2][0]*m_aafEntry[2][0]);
m_aafEntry[0][0] *= fInvLength;
m_aafEntry[1][0] *= fInvLength;
m_aafEntry[2][0] *= fInvLength;
// compute q1
Real fDot0 =
m_aafEntry[0][0]*m_aafEntry[0][1] +
m_aafEntry[1][0]*m_aafEntry[1][1] +
m_aafEntry[2][0]*m_aafEntry[2][1];
m_aafEntry[0][1] -= fDot0*m_aafEntry[0][0];
m_aafEntry[1][1] -= fDot0*m_aafEntry[1][0];
m_aafEntry[2][1] -= fDot0*m_aafEntry[2][0];
fInvLength = Math::InvSqrt(m_aafEntry[0][1]*m_aafEntry[0][1] +
m_aafEntry[1][1]*m_aafEntry[1][1] +
m_aafEntry[2][1]*m_aafEntry[2][1]);
m_aafEntry[0][1] *= fInvLength;
m_aafEntry[1][1] *= fInvLength;
m_aafEntry[2][1] *= fInvLength;
// compute q2
Real fDot1 =
m_aafEntry[0][1]*m_aafEntry[0][2] +
m_aafEntry[1][1]*m_aafEntry[1][2] +
m_aafEntry[2][1]*m_aafEntry[2][2];
fDot0 =
m_aafEntry[0][0]*m_aafEntry[0][2] +
m_aafEntry[1][0]*m_aafEntry[1][2] +
m_aafEntry[2][0]*m_aafEntry[2][2];
m_aafEntry[0][2] -= fDot0*m_aafEntry[0][0] + fDot1*m_aafEntry[0][1];
m_aafEntry[1][2] -= fDot0*m_aafEntry[1][0] + fDot1*m_aafEntry[1][1];
m_aafEntry[2][2] -= fDot0*m_aafEntry[2][0] + fDot1*m_aafEntry[2][1];
fInvLength = Math::InvSqrt(m_aafEntry[0][2]*m_aafEntry[0][2] +
m_aafEntry[1][2]*m_aafEntry[1][2] +
m_aafEntry[2][2]*m_aafEntry[2][2]);
m_aafEntry[0][2] *= fInvLength;
m_aafEntry[1][2] *= fInvLength;
m_aafEntry[2][2] *= fInvLength;
}
[/SOURCECODE]
hth,
Codemattic
However I dont believe...
Quote:Originally posted by Mark Levinis completely accurate. If you need to have a matrix which will accumulate errors you *can* orthonormalize it. Its slow - but again as you posted - you dont need to do it every frame because it takes some time for a matrix to become undone.
"Normalizing the matrix" means clearing it to the identity matrix and setting it explicitly to the rotation you want, instead of multiplying a rotation matrix with very small numbers a hundred thousand times.
I use the math library called FreeMagic - which you can get at <http://www.magic-software.com> and it has this method for dealing with 3x3 matricies (and you really only need to apply this to the 'rotational' 3x3 section of OpenGL's 4x4 matrix)
[SOURCECODE]void Matrix3::Orthonormalize ()
{
// Algorithm uses Gram-Schmidt orthogonalization. If 'this' matrix is
// M = [m0|m1|m2], then orthonormal output matrix is Q = [q0|q1|q2],
//
// q0 = m0/|m0|
// q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0|
// q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1|
//
// where |V| indicates length of vector V and A*B indicates dot
// product of vectors A and B.
// compute q0
Real fInvLength = Math::InvSqrt(m_aafEntry[0][0]*m_aafEntry[0][0]
+ m_aafEntry[1][0]*m_aafEntry[1][0] +
m_aafEntry[2][0]*m_aafEntry[2][0]);
m_aafEntry[0][0] *= fInvLength;
m_aafEntry[1][0] *= fInvLength;
m_aafEntry[2][0] *= fInvLength;
// compute q1
Real fDot0 =
m_aafEntry[0][0]*m_aafEntry[0][1] +
m_aafEntry[1][0]*m_aafEntry[1][1] +
m_aafEntry[2][0]*m_aafEntry[2][1];
m_aafEntry[0][1] -= fDot0*m_aafEntry[0][0];
m_aafEntry[1][1] -= fDot0*m_aafEntry[1][0];
m_aafEntry[2][1] -= fDot0*m_aafEntry[2][0];
fInvLength = Math::InvSqrt(m_aafEntry[0][1]*m_aafEntry[0][1] +
m_aafEntry[1][1]*m_aafEntry[1][1] +
m_aafEntry[2][1]*m_aafEntry[2][1]);
m_aafEntry[0][1] *= fInvLength;
m_aafEntry[1][1] *= fInvLength;
m_aafEntry[2][1] *= fInvLength;
// compute q2
Real fDot1 =
m_aafEntry[0][1]*m_aafEntry[0][2] +
m_aafEntry[1][1]*m_aafEntry[1][2] +
m_aafEntry[2][1]*m_aafEntry[2][2];
fDot0 =
m_aafEntry[0][0]*m_aafEntry[0][2] +
m_aafEntry[1][0]*m_aafEntry[1][2] +
m_aafEntry[2][0]*m_aafEntry[2][2];
m_aafEntry[0][2] -= fDot0*m_aafEntry[0][0] + fDot1*m_aafEntry[0][1];
m_aafEntry[1][2] -= fDot0*m_aafEntry[1][0] + fDot1*m_aafEntry[1][1];
m_aafEntry[2][2] -= fDot0*m_aafEntry[2][0] + fDot1*m_aafEntry[2][1];
fInvLength = Math::InvSqrt(m_aafEntry[0][2]*m_aafEntry[0][2] +
m_aafEntry[1][2]*m_aafEntry[1][2] +
m_aafEntry[2][2]*m_aafEntry[2][2]);
m_aafEntry[0][2] *= fInvLength;
m_aafEntry[1][2] *= fInvLength;
m_aafEntry[2][2] *= fInvLength;
}
[/SOURCECODE]
hth,
Codemattic

