三次元変換行列(5)出直し
2008/05/12 22:03 - AS3.0
次にメソッドのコードです。
最低限必要なメソッドは、平行移動(translate)、拡大縮小(scale)、座標軸回転(rotateAxis)、行列合成(concat)、そして行列合成に関連して複製(clone)。以上五つ。 これは変わりません。
各メソッドコードの提示ですが、リライト版ではちょっと変えて、まずは行列合成(concat)から説明します。
そもそも行列合成とは何なのか。それは二つの行列の掛け算です。足し算ではありません。
コードの話に進む前に行列の掛け算について見てみます。
a と b の二つの項における加減乗除では、a、b が実数の場合、加算と乗算は演算子の右と左を入れ替えても結果は同じです。 しかし減算と除算は演算子の右と左を入れ替えると、通常は同じ結果になりません。 とまぁここまでは算数レベル。
a + b = b + a a × b = b × a a - b ≠ b - a a ÷ b ≠ b ÷ a
数学的には、加算・乗算のように項の入れ替えが可能な場合を「交換法則を満たす」といい、減算・除算のように項の入れ替えが不可能な場合を「交換法則を満たさない」と言うそうです。
で肝心の行列の掛け算はというと、交換法則を満たさないとのこと。
つまり concat のコードを書く際には、現在の状態を示している行列と、その行列に対して移動なり回転なりを反映させるための行列を、どういう順番で掛け算するのか間違えんようせんとイカンわけです。
で、どういう順番で計算するのさ、ということですが、「コンピュータゲームの数学」75、76ページでは、複数の行列変換をおこなう場合、最初におこなう行列変換から反映させる、という意味のことが書いてあります。
ということは以下の順番になるということですね。
これから反映させようとしている行列×今現在の行列
よってコードはこうなります。
public function concat( mat:Matrix3D ):void { var now:Matrix3D = this.clone(); _a = mat.a*now.a + mat.b*now.d + mat.c*now.g; _b = mat.a*now.b + mat.b*now.e + mat.c*now.h; _c = mat.a*now.c + mat.b*now.f + mat.c*now.i; _tx = mat.a*now.tx + mat.b*now.ty + mat.c*now.tz + mat.tx; _d = mat.d*now.a + mat.e*now.d + mat.f*now.g; _e = mat.d*now.b + mat.e*now.e + mat.f*now.h; _f = mat.d*now.c + mat.e*now.f + mat.f*now.i; _ty = mat.d*now.tx + mat.e*now.ty + mat.f*now.tz + mat.ty; _g = mat.g*now.a + mat.h*now.d + mat.i*now.g; _h = mat.g*now.b + mat.h*now.e + mat.i*now.h; _i = mat.g*now.c + mat.h*now.f + mat.i*now.i; _tz = mat.g*now.tx + mat.h*now.ty + mat.i*now.tz + mat.tz; }
now は clone によって生成された行列、つまり現在の状況を保持した行列です。
引数の mat はこれから新たに反映させたい内容を保持した行列です。
ということなので mat * now の順番で乗算をおこなえば良いわけで、上記コードのような計算式になります。
行列の乗算方法については、ウィキペディアの「行列」の「積の計算例」をご参照ください。
次に clone メソッド。
これは簡単です。 新規生成する行列オブジェクトのコンストラクタ引数に現在の行列の内容を突っ込むだけ。
public function clone():Matrix3D { return new Matrix3D( _a , _b , _c, _d , _e , _f, _g , _h , _i, _tx, _ty, _tz ); }
続く。