Determining yaw, pitch, and roll from a rotation matrix

Hi :slight_smile:

I have 3x3 rotation matrix:
Matrix3f rotation = readFromFile();
which I can apply to my geometry in order to rotate my model, like this:
geometry.setLocalRotation(rotation);

However, what I would like to do, is calculate the yaw, pitch, and roll values of the rotation.
Is there an easy way to do that in jMonkey?

I could probably calculate that manually using some math like described here Determining yaw, pitch, and roll from a rotation matrix
but I suspect there is an easy way…

Cheers, Elg’

Hmm, calculate from your matrix? Or just assign (3-D Rotation :: jMonkeyEngine Docs)?

If you want to calculate it by hand, you can do so by calculating the angle between the axes of the reference frame and the axes of the axes of the body frame. Keep in mind that the sequence of calculation matters, therefore it is not possible to provide a generic solution, just an example (see below)

public double[] getYawPitchRoll(CartesianFrame referenceFrame) {

// Define the standard reference frame
if (referenceFrame==null)
referenceFrame=new CartesianFrame();

// x1 is the reference X-axis after the first rotation, it is on the xy-plane of
// the reference frame.
Vector3d x1=
referenceFrame.getXAxis().mult(bodyAxes.getXAxis().dot(referenceFrame.getXAxis())).add(
referenceFrame.getYAxis().mult(bodyAxes.getXAxis().dot(referenceFrame.getYAxis())));

x1.normalizeLocal();

// y12 is the reference Y-axis after applying the first and second rotation
// (which doesn’t change in between)
Vector3d y12=referenceFrame.getZAxis().cross(x1);
y12.normalizeLocal();

// 1st: Calculate pitch angle
double pitch=x1.angleBetween(bodyAxes.getXAxis());

// Pitch in negative range
if (bodyAxes.getXAxis().dot(referenceFrame.getZAxis())<0)
pitch=-pitch;

if (Double.isNaN(pitch))
pitch=0.;

// 2nd: Calculate yaw angle
double yaw=referenceFrame.getYAxis().angleBetween(y12);

if (bodyAxes.getXAxis().dot(referenceFrame.getYAxis())>0)
yaw=-yaw;

if (Double.isNaN(yaw))
yaw=0.;

// 3rd: Calculate roll angle
double roll=y12.angleBetween(bodyAxes.getYAxis());

if (bodyAxes.getZAxis().dot(referenceFrame.getYAxis())>0)
roll=-roll;

if (Double.isNaN(roll))
roll=0.;

return new double {roll, pitch, yaw};
}

Do you mean something like:

float roll = geometry.getLocalRotation().toAngleAxis(Vector3f.UNIT_X);
float yaw = geometry.getLocalRotation().toAngleAxis(Vector3f.UNIT_Y);
float pitch = geometry.getLocalRotation().toAngleAxis(Vector3f.UNIT_Z);

(or make Quaternion instance out of my matrix, without interaction with geometry)

will that work?

Edit:
No, this is totally wrong. The argument of toAngleAxis() is supposed to store the output of the method.

The formulas for computing yaw, pitch, and roll from a rotation matrix will depend on your conventions and definitions:

  • which axes are chosen for the craft’s forward and up directions,
  • whether the coordinate system is left-handed or right-handed,
  • how positive angles are defined,
  • whether rotations combine intrinsically or extrinsically, and
  • the order in which the rotations are applied.

If you’re not fussy about the details, you might try using a Quaternion as an intermediary:

    Quaternion q = new Quaternion();
    q.fromRotationMatrix(matrix3f);
    float[] angles = q.toAngles(null);
1 Like

The really important question is: why?

Mathematically, as seen above, there are numerous ways to do it… but for the very most common reason people WANT to do this: the answer is impossible. (And there are other solutions that start earlier in your process.)

So please explain what you are actually trying to do.

3 Likes

Sorry for being so quiet last two days. I was trying to gain a better understanding of the source of the issue I’m solving here.

I’m rendering an old game. All the game data: like 3D models (.obj files), positions of objects in game world - seem to be stored in left-hand coordinate system, while jMonkeyEngine uses right-hand coordinate system. Or the other way around.

At first, I thought I could easily handle this by for example negating the Z coordinate. Now I’m loading objects (some 3D models, like tree or bench) into the game world by reading game files which contain the [x,y,z] coordinates of the objects. The problem is, that the data also contains rotation information in form of rotation matrix, as some of the objects are rotated/shifted, etc.
So I was trying to somehow convert the rotation matrix from the old coordinate system, to the new one (the one jME uses). My idea was to split the rotation matrix into yaw,pitch,roll values, negate one of them, and then use it to rotate the object. I’m not sure if that would work even if I managed to calculate the three angles properly.
I don’t have knowledge of how was the rotation matrix defined in the original game, what was the order of rotations, was it clockwise or counter clockwise, etc.

Converting a rotation matrix from left hand to right hand can actually be pretty easy.

…the rest of the data, I don’t know. Sometimes it will also flip the polygon winding.

These are solvable problems that do not require conversion to (imperfect) yaw/pitch/roll.

The other thing that might catch you is if the rotation matrix if column major versus row major.

Whether row major or column major the (rows or columns respectively) represent the three coordinate axes (x, y, z) of that rotation. So changing handedness can be as easy as flipping the signs of one of the columns/rows.

1 Like

I’m now trying this:

            var oldToNew = new Matrix3f();
            oldToNew.loadIdentity();
            oldToNew.set(2, 2, -1f);            
            var newToOld = oldToNew.invert();            
            holder.setLocalRotation(oldToNew.mult(rot).mult(newToOld));

where rot is the rotation matrix stored in game files.
I think it basically does what you said: one column gets multiplied by -1. Although I do the conversion to original system, rotate, then convert back to current system.

I’m 95% sure it is OK now, I will have to run the original game tomorrow and perform detailed comparison.

Another thing is that I’m having issues with texture mapping. I’m not sure if I’m suppose to do something about the mapping, in case I negated the Z coordinate of the models…

Yeah, that is similar that we have to do in OpenKeeper. We just modify the matrix columns, multiply with -1. Shame you didn’t start with this information :smiley:

1 Like

yea…
I didn’t realise that using different coordinate systems is even a thing :smiley: I just thought the game I’m dealing with is being weird in its own way by storing values in opposite order [z,y,x] instead of [x,y,z] (as swapping x with z also solves the issue, in a way).

1 Like

Opengl vs directx coordinate system. a nice example of " no, we do it different even there are no benefits" decisions

Anyway, thank you everyone for your comments - it helped me to revise my perspective on the issue.
:heart:

1 Like

Did you also had to do anything about texture mapping coordinates?
I’m still having issues with texturing…

For models we also do some math with vertices and normals. That I believe lets us load textures normally. Also when we apply the texture, we say that do not flipY (TextureKey (jMonkeyEngine3))… Is that the magic?
(https://github.com/tonihele/OpenKeeper/blob/master/src/toniarts/openkeeper/tools/convert/KmfModelLoader.java#L207-L222)

Dungeon Keeper 2 models are in DirectX coordinate system (maybe, can’t remember anymore). Some values in different order and some in opposite coordinates.

2 Likes

Beyond tonihele’s answer (which is probably right), we would have to know what “issues” is.

Texture coordinates should not be affected by the vertex coordinate system. So the most likely cause is that the texture is flipped upside down which is easily remedied on load of the texture.

1 Like

It’s hard to say… it looks too weird and random to draw a conclusion.
I will try to flip vertically and see if it helps.

For video game development, a picture is worth a bajillion-kajillion-mahjillion words.

I could probably diagnose a thousand different problems with only two images “This is what it looks like” and “this is what it should look like”.

3 Likes

Let put it to the test!


what’s the diagnosis doctor Gamedev? :wink:

Yes it is! :slight_smile:

thanks :heart:

2 Likes

From those images, my diagnosis would have been that the textures had been flipped.

2 Likes