どのようにして変換行列から方向を抽出できますか?


10

4x4の変換行列Mがあり、Mで変換したときの球の形状を確認したい(球は原点にあり、半径は1です)。

Mに(0,0,0,1)を乗算するだけで中心を見つけることができます。

ただし、Mは球を押しつぶして回転させることができるため、半径が問題になります。結果として得られる楕円体の新しい半径を見つけるにはどうすればよいですか?オリエンテーションを見つける方法はありますか?

具体的には、変換された球を囲む境界球のサイズを知る必要があります。言い換えると、| M * V-M *(0,0,0,1)|の最大値は何ですか。ここで、Vは単位ベクトル(元の球上の点)です。


1
変換された軸ベクトルの長さを計算することはできませんか?(マトリックスの回転部分の3列)バウンディング球の半径は、最長のベクトルの長さに等しくなります。
バート

いいえ、それは正しいとは思いません。最長の方向は軸合わせされていない可能性があります。(あなたがそれを押しつぶした、回転させた、もう一度押しつぶした、さらに回転させた、などを想像してください)
CaptainCodeman

うーん、それが問題かどうかわからない。なんとか納得できたら、今日は後で答えを書きます。;)
バート

問題は、SCALE変換を行う場合、M行列の基本ベクトルが互いに直交している必要がないことです。
GPUquant 2013

回答:


6

数学的には、求めている量は演算子ノルムと呼ばれます。残念ながら、その単純な公式はありません。それが完全に一般的なアフィン変換である場合、たとえば、回転と不均一なスケールの任意の組み合わせを任意の順序で持つ可能性がある場合、特異値分解を使用する以外に方法はありません。SVDをマトリックスに適用すると、最大の特異値は、結果として得られる楕円体の最大半径になります。他の特異値は他の2つの半径にもなり、SVDプロシージャは軸の方向を抽出することもできます。

SVDの実装は、固有値を見つけることを伴うため、気の弱い人には向いていません。必要なのが特異値そのものであれば、それらはM ^ T * Mの固有値の平方根になります。したがって、3x3固有値ソルバーが手元にある場合、または固有のソルバーを記述してもかまわない場合は、それを使用できます。軸の方向も抽出する場合は、固有ベクトルも見つける必要があるため、さらに複雑になります。そのWikipediaの記事には、SVDを実行するためのライブラリへのリンクのリストがあり、そのうちの1つをプロジェクトで使用できる場合があります。

不均一なスケールが最大で1回発生し、最初に適用される変換であるようにマトリックスの形式が制限されている場合、つまり列ベクトルを使用しているときに最も右にある場合、これを単純化して、長さを調べるだけです。変換された軸ベクトル。その場合、単独-つまり、単一の不均一なスケールの後に回転、反射、および均一なスケールのシーケンスが続く-軸ベクトルだけを見れば、正しい答えが得られます。


おかげで、細かい対応に感謝します。他の回答で提供されている分解はどこで機能しませんか?
CaptainCodeman 2013

2
@CaptainCodemanもう1つの答えは、3番目の段落で説明したように、変換された軸ベクトル(つまり、行列の列)を調べることです。回転後に元の軸に沿ってスケーリングが適用されないため、回転後に不均一なスケールがある場合は失敗します。
Nathan Reed、

2

おそらく、マトリックスからスケールファクターを抽出し、そのコンポーネントの最大値を使用します。SRT(Scale-Rotation-Translation)マトリックスを使用すると、次のように実行できます。

glm::mat4 m = ...;
// Extract col vectors of the matrix
glm::vec3 col1(m[0][0], m[0][1], m[0][2]);
glm::vec3 col2(m[1][0], m[1][1], m[1][2]);
glm::vec3 col3(m[2][0], m[2][1], m[2][2]);
//Extract the scaling factors
glm::vec3 scaling;
scaling.x = glm::length(col1);
scaling.y = glm::length(col2);
scaling.z = glm::length(col3);

float scaleFactor = MAX(scaling.x, MAX(scaling.y, scaling.z));

http://wklej.org/id/950061/に基づく-OpenGLで行列が乗算される順序に基づいて並べられた名前を使用するため、名前はdecomposeTRSであり、decomposeSRTではありません)。

これで、元の球の半径にscaleFactorを掛けることができ、境界球ができました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.