Game Development Community

Get Rotation angles

by Steve Lamperti · in Torque Game Engine · 07/13/2005 (12:28 pm) · 12 replies

Before I even ask my question I would like to acknowledge that my knowledge of 3D math is nill.
What I am trying to do is to be able to retrieve the values of angles of rotation around the three axes.

Here's the code that I currently have that is not working correctly:

// JSL - find the X rotation value
F32	ExtendBase::getXRotation()
{
	Point3F rot;

	const MatrixF& tmat = getTransform();
	tmat.getColumn(3, &rot);

	return(mAtan(rot.y, -rot.z));
}


// JSL - find the Y rotation value
F32	ExtendBase::getYRotation()
{
	Point3F rot;

	const MatrixF& tmat = getTransform();
	tmat.getColumn(3, &rot);

	return(mAtan(rot.x, -rot.z));
}


// JSL - find the z rotation value
F32	ExtendBase::getZRotation()
{
	Point3F rot;

	const MatrixF& tmat = getTransform();
	tmat.getColumn(3, &rot);

	return(mAtan(rot.x, -rot.y));
}

I pieced this together from threads on the forum, but obviously did not really understand it well enough to get it working.

If someone who does have a grasp of 3D math would like to comment on what particular stupid things I am doing here, hopefully with some suggestions as to how to do the right things, I would appreciate it.

If there is a fundamental conceptual problem, I would appreciate hearing about that as well.

(Also, of course, if I am missing some code that already does this, the name of that, or those routines, would be a fine answer.)

Thanks,

#1
07/13/2005 (12:32 pm)
Try replacing the '3' in the three tmat.getColumn's
with 1, 2, and 3. or 0, 1, and 2.

ie

.
.
tmat.getColumn(1, &rot);  // maybe should be 0 ?
.
.
tmat.getColumn(2, &rot);  // maybe should be 1 ?
.
.
tmat.getColumn(3, &rot);  // maybe should be 2 ?
.
.

there may be some other problem, but i'd start with that.
#2
07/13/2005 (1:37 pm)
Hi Steve,

From my limited knowledge, the TGE matrix is a matrix (a bunch of vectors together), so when you ask for a column of the matrix, you are getting a vector back. I think you want columns 0, 1 and 2 of the matrix. More specifically, the TGE matrix (from what I can tell) is setup like this:

With vectors p, q, and r (representing the x, y and z-axis), and t representing translation (which is position). The second letter is the x/y/z component for these 4 vectors.

axis
(x y z) pos
--------------
px qx rx tx
py qy ry ty
pz qz rz tz
0 0 0 1


So, if you want the position of the object, you grab the 4th column in the matrix, like:
tmat.getColumn(3, &pos);

Since the matrix is stored in an array, the 4th column is actually accessed with "3", since arrays start at zero.

If you want the forward vector of your object, you grab the object y axis (q vector), like this:
tmat.getColumn(1, &pos); // (column 2)

Hope that makes sense!
- Drew
#3
07/13/2005 (1:42 pm)
@Orion and Drew,

Thanks. I have made this change, and it makes sense. I still am not getting correct numbers from my functions, but they seem better. I am betting that my next challenge is trying to come up with good args for the mAtan function.
#4
07/13/2005 (3:12 pm)
.. this may be fairly non-trivial, it turns out.
i'm a bit surprised it's not in torque somewhere already.
(it may be, i'm no expert)

BUT

try normalizing the vectors before doing the atan2.
#5
07/13/2005 (3:28 pm)
I read about the atan2 function on a posting somewhere, but unfortunately I can't find it any more. I'll try normalizing, but I have to say that I agree with both the observation that it's non-trivial, and the surprise that it's not already in the engine somewhere.
#6
07/13/2005 (4:41 pm)
In editor/worldEditor.cc you'll find:

EulerF extractEuler(const MatrixF & matrix)
{
   const F32 * mat = (const F32*)matrix;
   
   EulerF r;   
   r.x = mAsin(mat[MatrixF::idx(2,1)]);

   if(mCos(r.x) != 0.f)
   {
      r.y = mAtan(-mat[MatrixF::idx(2,0)], mat[MatrixF::idx(2,2)]);
      r.z = mAtan(-mat[MatrixF::idx(0,1)], mat[MatrixF::idx(1,1)]);
   }
   else
   {
      r.y = 0.f;
      r.z = mAtan(mat[MatrixF::idx(1,0)], mat[MatrixF::idx(0,0)]);
   }

   return(r);
}

FYI: For 1.4 this should be added as a function of MatrixF.
#7
07/13/2005 (5:32 pm)
@Matthew,

I tried implementing calls to extractEuler in my code, and I'm still not seeing consistently correct results.
Here's my latest code:

// JSL - find the X rotation value
F32	ExtendBase::getXRotation()
{
	Point3F rot;

	const MatrixF& tmat = getTransform();
	rot = extractEuler(tmat);
	return(rot.x);
}


// JSL - find the Y rotation value
F32	ExtendBase::getYRotation()
{
	Point3F rot;

	const MatrixF& tmat = getTransform();

	rot = extractEuler(tmat);
	return(rot.y);
}


// JSL - find the z rotation value
F32	ExtendBase::getZRotation()
{
	Point3F rot;

	const MatrixF& tmat = getTransform();

	rot = extractEuler(tmat);
	return(rot.z);
}

Did I maybe miss something in how to use this? Or perhaps there are cases under which it doesn't work.
For example, if I rotate my object to 0, 0, 0, and call these functions, they return 0, -0, -0, which is fine,
0, 0, 3.142 returns 0, 0, -3.14, also fine
but
3.142, 0, 0, returns -.0004, -3.14, -3.14, which is not so fine.

Thanks for all the responses, by the way.
#8
07/13/2005 (5:47 pm)
Isn't PI,0,0 equivalent to 0, -PI, -PI?

There are multiple ways of representing the same rotation in Euler angles.
#9
07/13/2005 (5:51 pm)
Incidentally, it's on the list, #150.
#10
07/14/2005 (9:00 am)
Thanks for all the help. It looks like the extractEuler code is working fine. There seems to be some issue with my setRotation code, which made me not recognize that, as Ben says, PI, 0, 0, should be the same as 0, -PI, -PI.
#11
12/18/2005 (7:34 am)
Could anyone tell me what extractEuler() do? even I look at the code I still have no idea, maybe because my knowledge about the 3d math is zero.
#12
12/18/2005 (3:34 pm)
It converts the rotation in a matrix from being implicitly stored in some vectors to being represented as an euler angle (ie, pitch, yaw, roll in radians).