Game Development Community

Euler Angles, Matrixes and rolling.

by Stefan Lundmark · in Torque Game Engine · 01/04/2008 (8:31 am) · 6 replies

Hi guys,

I never studied these kind of mathematical subjects back in school and my understanding of Matrixes is lacking.

I'm trying to make a shape roll around it's Y-axis, like the Player does with it's Z-axis, while also being able to rotate around it's X-axis (Pitch). This has been very frustrating so far.

void RotatingShape::setPosition(const Point3F& pos,const Point3F& rot)
{
    MatrixF xRot, yRot;
    MatrixF temp; 
    xRot.set(EulerF(rot.x, 0, 0));
    yRot.set(EulerF(0, rot.y, 0));
   
    temp.mul(yRot, xRot); // <- Problem?
    temp.setColumn(3, pos); 

    Parent::setTransform(temp);
    mRot = rot;
}

Using the above code, the object now rolls, but it breaks as soon as I use pitch. It looks like it's using the World coords to rotate but it clearly doesn't since it's using getTransform () just like Player does. If I turn the shape around, like it's now pointing backwards, rolling seems to be reversed. And if I point the shape straight up, it tilts instead of rolls.

In another thread someone suggested that I have to use QuatF which FlyingVehicle is using, but shouldn't it be possible with Point3F as well? I've tried QuatF unsuccessfully and FlyingVehicle is too heavy for my needs.

The thing I noticed is that if I change the order of multiplication of the matrix to begin with xRot instead of yRot, yaw starts behaving like roll did previously, and roll works instead.

Can anyone give me any directions? I'm seriously stuck.

#1
01/04/2008 (9:11 am)
Try:
void RotatingShape::setPosition(const Point3F& pos,const Point3F& rot)
{
   //Get the current transform matrix
   MatrixF mat=getTransform();

   //Create a matrix from the rotation parameter
   //Note this rotation is a relative change from 
   //the last time this function was called
   MatrixF change(EulerF(rot));

   //Multiply the matrices to do the rotation
   mat.mul(change);

   //Apply the linear transform
   mat.setColumn(3, pos); 

   //Apply the final matrix to the object
   setTransform(mat);

   //Save the rotation as Euler???
   mRot = mat.toEuler();
}

Basically what you are experiencing is Gimbal lock. Where one or more of the object's axii are aligned with the world and not the object. This is due to the order of the rotations you apply to the object. Using Euler angles instead of a Matrix or a Quat will cause this problem.

Since the order of the transformation is important, the changes must be made incrementally and the resulting matrix stored. This is why I first pull the current transform matrix, and then apply the rotation and then translation to that matrix before reapplying that final matrix to the object.

Are you using mRot to pass as a parameter in subsequent calls to this function? If so that is unnecessary, just send zeros.

The parameters to the function must be relative changes.

Gabriel
#2
01/04/2008 (10:12 am)
Big thanks to you Gabriel!

I use mRot for packUpdate() and calculating delta's, identical to how the Player class handles it.
Unfortunatly, all I get is jitter and the transforms keep changing eventhough no moves come in.
I suppose it's not due to setPosition () but somewhere else which doesn't cooperate with the changes.

This is what I ended up with if it can be helpful for anyone else in the future.
//Get the current transform matrix   
	MatrixF mat = getTransform();   
	
	//Create a matrix from the rotation parameter   
	//Note this rotation is a relative change from    
	//the last time this function was called
	EulerF tempRot (rot);
	MatrixF change(tempRot);   
	
	//Multiply the matrices to do the rotation   
	mat.mul(change);   
	
	//Apply the linear transform   
	mat.setColumn(3, pos);    
	
	//Apply the final matrix to the object   
	Parent::setTransform(mat);   
	
	//Save the rotation as Euler???   
	//mRot = mat.toEuler();

(mRot is required to contain the last used rotation to be able to interpolate, but I disabled it for the purpose of testing.)
#3
01/05/2008 (11:37 am)
There is a possible error in my code above.

//Multiply the matrices to do the rotation
   mat.mul(change);

   //Apply the linear transform
   mat.setColumn(3, pos);

Should be replaced with:
//Apply the linear transform
   change.setColumn(3, pos); 

   //Multiply the matrices to do the rotation
   mat.mul(change);

That way the linear transform is relative too. The networking and client prediction creates other problems when transforming an object especially if you want smooth movement.

What is your base class for this?

Gabriel
#4
01/06/2008 (5:34 am)
Sorry to bump. But isn't there a quaternion class in Torque to avoid Gimbal Locks (CMIIW)? Why don't use it? AFAIK to avoid Gimbal Locks, we should use quaternions, right? I'm still re-learning my 3D graphics (especially quaternion). Haven't used them for ages. :D
#5
01/06/2008 (9:04 am)
Matrices like Quats don't suffer from Gimbal Lock, and can hold additional transform information such as linear and scale. Quats however can be used for smooth interpolating between orientations, something you can't do with Matrices.

Gabriel
#6
01/06/2008 (2:31 pm)
Gabriel,

I'm using the Player class with the addition that it can move vertically now, pretty much like the camera class can.

Normally, moves are directly put into mRot and then applied to the transform in setPosition (). What I'm trying to do is to grab the current transform and put it into a temporary Matrix, apply rotation to the Matrix without gimbal locking, then grabbing rotation via getColumn to get it in Euler and put it into mRot.

That should play well with interpolation, I'm not sure I can get it to work.
I'll try the above code soon. Thanks again.

Edit: It's too much work for someone who's never studied Matrixes before, so I'm doing as I've been recommended and moving to the FlyingVehicle class. Just have to simplify rigid because it's definatly not something I want.

I want to thank you for all your help Gabriel, you've been very helpful.