web-dev-qa-db-ja.com

マトリックスを右手座標系から左手座標系に変更する

4x4マトリックスを右手系から変更します。
xは左右、yは前後、zは上下

左手系の場合:
xは左と右、 z 前後です y 上下です。

ベクトルの場合は簡単です。yとzの値を交換するだけですが、行列の場合はどうすればよいでしょうか。

26
cmann

それについてもう少し説明してみましょう。 z軸が上を向いているBlenderから、y軸が上を向いているOpenGLにモデルをエクスポートする必要があります。

すべての座標(x、y、z)は単純です。 yとzの値を入れ替えるだけです:(x、z、y)。
すべてのy値とz値を入れ替えたため、使用するすべての行列も反転させて、同じ効果が得られるようにする必要があります。

多くの検索を行った後、最終的に gamedev で解決策を見つけました:

マトリックスが次のようになっている場合:

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

左から右または右から左に変更するには、次のように反転します。

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

私は現在同様の問題に直面しているので、あなたの問題は理解できたと思います。

  • まず、Zが上にある空間でベクトルを変換するワールドマトリックス(たとえば、ワールドマトリックス)から始めます。

  • Yが上にあるスペースができたので、古い行列をどうするかを知りたいと思います。

これを試して:

与えられた世界行列があります

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

このマトリックスは、ベクターのYおよびZコンポーネントを変更します

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

あなたはこれを探しています:

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

結果は、以下に掲載されているのと同じ行列cmannです。しかし、次の計算を組み合わせると、これはより理解しやすいと思います。

1)YとZを切り替える

2)古い変革を行う

3)ZとYを元に戻す

13
Gerrit

多くの場合、マトリックスを1つの順/右/上規則のセットから別の順/右/上規則のセットに変更する必要があります。たとえば、ROSはz-upを使用し、Unrealはy-upを使用します。このプロセスは、利き手フリップを行う必要があるかどうかに関係なく機能します。

「右利きから左利きに切り替える」という表現はあいまいであることに注意してください。多くの左利きの前方/右/上規則があります。例:forward = z、right = x、up = y;およびforward = x、right = y、up = z。あなたは本当にそれを「ROSのforward/right/upの概念をUnrealのforward/right/upの概念に変換するにはどうすればよいか」と考えるべきです。

したがって、規則を変換するマトリックスを作成するのは簡単な仕事です。それを行ったとしましょう。

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

OPにROSからのマトリックスがあり、彼女がアンリアルでそれを使用したいとします。彼女の元の行列はROSスタイルのベクトルを受け取り、それにいくつかのことを行い、ROSスタイルのベクトルを出力します。彼女は、Unrealスタイルのベクトルを受け取り、同じことを行い、Unrealスタイルのベクトルを出力する行列が必要です。これは次のようになります。

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

これが機能する理由はかなりはっきりしているはずです。アンリアルベクトルを取り、それをROSスタイルに変換すると、ROSスタイルのマトリックスを使用できるようになります。これによりROSベクトルが得られ、これをアンリアルスタイルに変換します。

一般的なケースでは、rosFromUnreal!= unrealFromRosであるため、Gerritの回答は完全には一般的ではありません。単一の軸を反転するだけの場合は当てはまりますが、X-> Y、Y-> Z、Z-> Xの変換などの場合は当てはまりません。正しいメンバーだけを反転させる特別な関数を作成しようとするよりも、これらの規則の切り替えを行うために常に行列とその逆を使用する方がエラーが発生しにくいことがわかりました。

この種の行列演算inverse(M) * X * Mはよく出てきます。これは「基本の変更」操作と考えることができます。詳細については、 https://en.wikipedia.org/wiki/Matrix_similarity を参照してください。

5
Paul Du Bois

Unity SteamVR_Utils.RigidTransformをROS geometry_msgs/Poseに変換する作業をしており、Unityの左手座標系をROSの右手座標系に変換する必要がありました。

これは、座標系を変換するために私が書いたコードです。

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

もともとは@bleaterのマトリックスの例を使用しようとしましたが、機能させることができませんでした。私がどこかで間違いを犯したかどうかを知りたいです。

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

左からマトリックスを掛けるか、右からマトリックスを掛けてポイントを変換するかによって異なります。

左から乗算する場合(例:Ax = x '、Aは行列、x'は変換された点)、2番目と3番目の列を交換するだけです。右から乗算する場合(例:xA = x ')、2番目と3番目の行を交換する必要があります。

ポイントが列ベクトルの場合は、最初のシナリオです。

1
tugudum

右利きと左利きの間で座標空間を交換するには、sin係数を-sinに変更します

0
Yesman