PDA

View Full Version : Rotation about arbitrary axis (loss of precision?)



dogdemir
02-23-2009, 01:53 PM
Hi all,
I'm using Euler's rotation matrix for rotation about an arbitrary 3D axis. The problem is that if I rotate for a long time or in great angles, it seems like the precision is lost (at least that's what I think the problem is) and the model starts scaling up quickly. What do you guys think about a way of fixing this?

Thanks,

md2model1_->rotate( dt * 10, Vec3D( 1, 1, 0 ) );



void
Entity::rotate( float angle, Vec3D axis )
{
Mat44 tMat;

float c = cos(angle);
float s = sin(angle);
float mc = 1 - c;
float axy = axis.y * axis.x;
float axz = axis.z * axis.x;
float azy = axis.z * axis.y;
float saxx = s * axis.x;
float saxy = s * axis.y;
float saxz = s * axis.z;
float mxaxysqr = mc * axis.y * axis.y;
float mazy = mc * azy;
float maxz = mc * axz;
float maxy = mc * axy;

tMat.x11 = c + mc * axis.x * axis.x;
tMat.x12 = maxy - saxz;
tMat.x13 = maxz + saxy;

tMat.x21 = maxy + saxz;
tMat.x22 = c + mxaxysqr;
tMat.x23 = mazy - saxx;

tMat.x31 = maxz - saxy;
tMat.x32 = mazy + saxx;
tMat.x33 = c + mxaxysqr;

//Apply the transformation matrix to the model's xformation.
tMatrix_ = tMatrix_ * tMat;

//Save the new axis.
xAxis_ = tMat * xAxis_; xAxis_.normalize();
yAxis_ = tMat * yAxis_; yAxis_.normalize();
zAxis_ = tMat * zAxis_; zAxis_.normalize();
}

trinitrotoluene
02-23-2009, 03:56 PM
One thing you can do is to accumulate the total angle in a variable and then use it as a parameter for your rotate function. But you have to modify your rotate function to do that because when you call model->rotate(angle,axis) you multiply the current transform with the previous transform. Or if you have a load identity function to make tMatrix equal to identity after each iteration of your rendering loop, you can do something like this:



total_angle += dt * 10;
md2model1_->loadIdentity();
md2model1_->rotate(total_angle, Vec3D( 1, 1, 0 ) );

dogdemir
02-23-2009, 07:58 PM
True but that does not work for rotation around different axis.

trinitrotoluene
02-24-2009, 08:18 AM
I think the only solution is to use quaternion (http://en.wikipedia.org/wiki/Quaternion) to represent rotation. Look at this paper (http://www.cs.cmu.edu/~baraff/sigcourse/notesd1.pdf) at section 4 page 21. That section of the paper explain why quaternion are better than matrix to describe rotation.

Hope that help.

dogdemir
02-24-2009, 10:33 AM
Thanks, I'll check it out.

dogdemir
02-25-2009, 08:16 PM
So I did added quaternions to my code however; I am having a hard time appending quaternions. If I do one rotation, everything works fine until I start doing multiple.

Below is the function that rotates a quaternion by a certain angle around an axis:



void
Quaternion::rotate( float angle, Vec3D axis )
{
Quaternion rotQuat( cos( angle / 2.f ), axis * sin( angle / 2.f ) );
Quaternion result = rotQuat * ( *this ) * rotQuat.inverse();
ijk = result.ijk;
r = result.r;

normalize();
}

Do you think there is anything wrong with this? I am sure that conversion to matrix, quaternion multiplication and all the rest is just fine.

Edit:

Ok, this rotates a vector:
Quaternion result = rotQuat * ( *this ) * rotQuat.inverse();

And this rotates the quaternion:
Quaternion result = rotQuat * ( *this );

My problem was with my constructor where I was initializing the real part to 0.5 instead of 1.

scratt
02-26-2009, 07:29 PM
For future reference.. There is a very nice Quaternion implementation in the OpenSceneGraph API. I used it to solve a couple of problems with new functions in my maths library the other day. Code is so much easier to read than maths papers! :)