1-7 座標変換其の弐


 

理解する気の無い者に、言う言葉もない

時田強武(リスクコンサルタント)



1.座標軸まわりの回転

 3DプログラムのHelloWorldともいうべき(誰がいっとるんじゃ)座標軸まわりの回転をやってみましょう。
座標軸まわりの回転というのは、XYZ軸のいずれかを軸として任意の角度回転させるやつです。
例としてZ軸回転を説明します。

(図1-7.1)

図中でZの左にあるでべそみたいなマークは、画面と直交する画面の奥に向かう軸を表します。
回転方向は、回転軸を正の側から見て時計回りを正とします。これを左手回転ということもあります。
左手の親指を立て、親指が回転軸の正の方向を向くように回転軸を握ったときの
他の四指の方向が回転の正方向です。
回転行列を作るには、回転後の座標軸の方向の単位ベクトルが分かれば、
それらを行ベクトルとした行列をつくればよいということでした。この場合はZ軸回転なので
Z' = Z = ( 0 0 1 )、X'とY'は図から明らかなようにX' = ( cosθ sinθ 0 )、
Y' = ( -sinθ cosθ 0 )となります。したがって、Z軸を中心としたθの回転を表す行列は

(式1-7.1)

で与えられます。

 念のため繰り返しますが、うちは左手座標・左手回転&行列は右から掛ける派です。
Direct3D派といってもいいかもしれません。大半の3Dプログラム解説書ではこの反対です。びるGまんせ〜
X軸、Y軸中心の回転もこれと同様に求められます。自分の宗派に合わせてやってみましょう。

 さてここで行列の積では結合法則が成り立つことを思い出してください。
例えばX軸回転->Y軸回転->Z軸回転と続けて回転させる処理が必要になったとします。
これを多数の頂点に施す場合、馬鹿正直に(ベクトル×行列)×3×頂点数とせず、
あらかじめ3つの回転行列を掛け合わせた

Mxyz = MxMyMz

をつくっておき、このMxyzを各頂点に掛けても同じ結果(丸め誤差は無視)が得られます。


 3次元空間の任意の向きは、向きを表すベクトルとXYZ軸との角度で表現することができます。
これをオイラー角とよんだりします。
オイラー角で指定された向きは、回転行列MxMyMzで表現できます。
もちろん実際に計算するときはXYZの回転行列を個別に求めて掛け合わせたりせず、

Mxyz(0 0) = cosYcosZ
Mxyz(0 1) = cosYsinZ


という感じでまとめて計算します。
ちなみにD3DXMatrixRotationYawPitchRollという関数ははこれと似たようなもんなんですが、
回転の順番がY->X->Zになっています。行列の積でいうとMyMxMzです。
行列の積では交換法則は成り立たないので、当然XYZの順番で回転させたときと
YawPitchRollは異なる結果になります。使う人は注意しましょう。


2.任意軸まわりの回転

 今度は任意のベクトルV()とスカラーθが与えられたとき、Vを回転軸とした
左手回転θを表すような行列Mを作ります。
考え方は、まず回転の対象となるベクトルP()をV()を座標軸の1つとする
座標系'に変換する行列Aを作ります。ここではV()を'のZ軸として、' = { X' Y' V }とします。
X',Y'はVをZ軸として左手座標をなすような未知の単位ベクトルです。
'をこのように定めると、->'の変換を行う行列Aは、'の各軸を列ベクトルとして

(式1-7.2)

となります。こうするとV()を軸とした回転は'ではZ軸を中心とした回転になり、
これを表す行列Mzは(式1-7.1)になります。
最後に'から狽ノ変換すればV()を軸とした回転を行ったことになります。
この変換は->'の逆変換であるのでA-1で表せ、Aは直交行列なのでA-1 = Atとなり、
結局Vを軸とした回転行列Mは、

(式1-7.3)

となります。

 さて未知のX'、Y'なんですが、{ X' Y' V }を左手座標をなす単位ベクトルとしているわけですから、

Y'×X' = V

Y'yX'z - Y'zX'y = Vx
Y'zX'x - Y'xX'z = Vy
Y'xX'y - Y'yX'x = Vx

が成り立ちます。また、AAt = Eであることからも明らかなように
Aの行ベクトルは単位ベクトルであり、互いに直交しています。したがって

X'x2 + Y'x2 + Vx2 = 1
X'xX'y + Y'xY'y + VxVy = 0

などが成り立ちます。
これらを用いて(式1-7.3)を計算すると、例えばM00は、

(式1-7.4)

となります。他の成分もがんばって計算すると、

(式1-7.5)

が得られます。


3.向きを直接的に指定する

 1-6.2回転でも触れたように、回転行列は向きを表しているともとれます。
というわけで今回は向きを直接指定して回転行列を作成します。
直接といっても左手座標をつくる3つの単位ベクトルを指定しろというのは意味が無いので、
3つの位置ベクトルを指定してもらうことにします。まず一つは座標系の原点を表す
位置ベクトルPで、もう一つはPから座標軸の1つの方向に伸ばした線上の点Dです。
"座標軸の1つ"は、例えばX軸であると約束します。するとX軸はNormalize(D-P)となります。
YZ軸はこれと直交するベクトルになりますが、これを決めるために例えばY軸の方向を
3つめの位置ベクトルUで指定してもらうことにします。
とはいってもPを通りX軸と直交する線上の点を指定しろというのも無理な話なので、
UはPを含むXY平面上で+Y側の点を指定してもらうことにします。
こうするとZ軸はX × ( U-P )を正規化したものになり、Y軸はZ × Xで決まります。
3つの位置ベクトルP、D、Uは同一直線上にはないとします。まとめると

X = Normalize( D - P )
Z = Normalize( X × ( U - P ) )
Y = Z × X


なんか文章で書くと分かりづらいですが、実際に動かしてみればなんてことはありません。
そこでサンプルプログラムですよ。



動作環境&操作方法はいつもと同じ。スペースキーを押しながら赤or緑の球をドラッグしましょう。


目次に戻る
1-8座標変換其の参