Changing a matrix from right-handed to left-handed coordinate system

59,939

Solution 1

Let me try to explain it a little better. I need to export a model from Blender, in which the z axis faces up, into OpenGL, where the y axis faces up.

For every coordinate (x, y, z) it's simple; just swap the y and z values: (x, z, y).
Because I have swapped the all the y and z values, any matrix that I use also needs to be flipped so that it has the same effect.

After a lot of searching I've eventually found a solution at gamedev:

If your matrix looks like this:

{ rx, ry, rz, 0 }  
{ ux, uy, uz, 0 }  
{ lx, ly, lz, 0 }  
{ px, py, pz, 1 }

To change it from left to right or right to left, flip it like this:

{ rx, rz, ry, 0 }  
{ lx, lz, ly, 0 }  
{ ux, uz, uy, 0 }  
{ px, pz, py, 1 }

Solution 2

I think I understand your problem because I am currently facing a similar one.

  • You start with a world matrix which transforms a vector in a space where Z is up (e.g. a world matrix).

  • Now you have a space where Y is up and you want to know what to do with your old matrix.

Try this:

There is a given world matrix

Matrix world = ...  //space where Z is up

This Matrix changes the Y and Z components of a Vector

Matrix mToggle_YZ = new Matrix(
{1, 0, 0, 0}
{0, 0, 1, 0}
{0, 1, 0, 0}
{0, 0, 0, 1})

You are searching for this:

//same world transformation in a space where Y is up
Matrix world2 = mToggle_YZ * world * mToggle_YZ;

The result is the same matrix cmann posted below. But I think this is more understandable as it combines the following calculation:

1) Switch Y and Z

2) Do the old transformation

3) Switch back Z and Y

Solution 3

It is often the case that you want to change a matrix from one set of forward/right/up conventions to another set of forward/right/up conventions. For example, ROS uses z-up, and Unreal uses y-up. The process works whether or not you need to do a handedness-flip.

Note that the phrase "switch from right-handed to left-handed" is ambiguous. There are many left-handed forward/right/up conventions. For example: forward=z, right=x, up=y; and forward=x, right=y, up=z. You should really think of it as "how do I convert ROS' notion of forward/right/up to Unreal's notion of forward/right/up".

So, it's a straightforward job to create a matrix that converts between conventions. Let's assume we've done that and we now have

mat4x4 unrealFromRos = /* construct this by hand */;
mat4x4 rosFromUnreal = unrealFromRos.inverse();

Let's say the OP has a matrix that comes from ROS, and she wants to use it in Unreal. Her original matrix takes a ROS-style vector, does some stuff to it, and emits a ROS-style vector. She needs a matrix that takes an Unreal-style vector, does the same stuff, and emits an Unreal-style vector. That looks like this:

mat4x4 turnLeft10Degrees_ROS = ...;
mat4x4 turnLeft10Degrees_Unreal = unrealFromRos * turnLeft10Degrees_ROS * rosFromUnreal;

It should be pretty clear why this works. You take a Unreal vector, convert it to ROS-style, and now you can use the ROS-style matrix on it. That gives you a ROS vector, which you convert back to Unreal style.

Gerrit's answer is not quite fully general, because in the general case, rosFromUnreal != unrealFromRos. It's true if you're just inverting a single axis, but not true if you're doing something like converting X->Y, Y->Z, Z->X. I've found that it's less error-prone to always use a matrix and its inverse to do these convention switches, rather than to try to write special functions that flip just the right members.

This kind of matrix operation inverse(M) * X * M comes up a lot. You can think of it as a "change of basis" operation; to learn more about it, see https://en.wikipedia.org/wiki/Matrix_similarity.

Solution 4

I have been working on converting the Unity SteamVR_Utils.RigidTransform to ROS geometry_msgs/Pose and needed to convert Unity left handed coordinate system to the ROS right handed coordinate system.

This was the code I ended up writing to convert coordinate systems.

var device = SteamVR_Controller.Input(index);
// Modify the unity controller to be in the same coordinate system as ROS.
Vector3 ros_position = new Vector3(
    device.transform.pos.z,
    -1 * device.transform.pos.x,
    device.transform.pos.y);
Quaternion ros_orientation = new Quaternion(
    -1 * device.transform.rot.z,
    device.transform.rot.x,
    -1 * device.transform.rot.y,
    device.transform.rot.w);

Originally I tried using the matrix example from @bleater, but I couldn't seem to get it to work. Would love to know if I made a mistake somewhere.

HmdMatrix44_t m = device.transform.ToHmdMatrix44();
HmdMatrix44_t m2 = new HmdMatrix44_t();
m2.m = new float[16];
// left -> right
m2.m[0] = m.m[0]; m2.m[1] = m.m[2]; m2.m[2] = m.m[1]; m2.m[3] = m.m[3];
m2.m[4] = m.m[8]; m2.m[5] = m.m[10]; m2.m[6] = m.m[9]; m2.m[7] = m.m[7];
m2.m[8] = m.m[4]; m2.m[9] = m.m[6]; m2.m[10] = m.m[5]; m2.m[11] = m.m[11];
m2.m[12] = m.m[12]; m2.m[13] = m.m[14]; m2.m[14] = m.m[13]; m2.m[15] = m.m[15];

SteamVR_Utils.RigidTransform rt = new SteamVR_Utils.RigidTransform(m2);

Vector3 ros_position = new Vector3(
    rt.pos.x,
    rt.pos.y,
    rt.pos.z);
Quaternion ros_orientation = new Quaternion(
    rt.rot.x,
    rt.rot.y,
    rt.rot.z,
    rt.rot.w);

Solution 5

After 12 years, the question is still misleading because of lack of description of axis direction.

What question asked for should probably be how to convert to . goal The answer by @cmann is correct for above question and @Gerrit explain the reason. But I want to explain how to get that conversion on transform matrix graphically.

We should be clear that orthogonal matrix contains both rotation matrix and point reflection. Thus they can be expressed as 4x4 matrix and obey to transform matrix multiplying order. "The matrix of a composite transformation is obtained by multiplying the matrices of individual transformations."

to contains both rotation matrix and point reflection. But we can get the composite transformation graphically.

According to above image, after transformation, in RhC(Right-handedCorrdinate) will be in LfC as below

where is a transform bring points expressed in above RhC to points expressed LhC. Now We are able to convert to accroding to transform matrix multiplying order as below image. enter image description here The result is exactly the same as @cmann's.

Result:

Share:
59,939
cmann
Author by

cmann

Updated on February 18, 2022

Comments

  • cmann
    cmann over 2 years

    I would like to change a 4x4 matrix from a right handed system where:
    x is left and right, y is front and back and z is up and down

    to a left-handed system where:
    x is left and right, z is front and back and y is up and down.

    For a vector it's easy, just swap the y and z values, but how do you do it for a matrix?