Rotation about arbitrary axis (loss of precision?)

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

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

True but that does not work for rotation around different axis.

I think the only solution is to use quaternion to represent rotation. Look at this paper at section 4 page 21. That section of the paper explain why quaternion are better than matrix to describe rotation.

Hope that help.

Thanks, I’ll check it out.

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.

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! :slight_smile: