三次元変換行列(7)
2008/05/13 21:31 - AS3.0
メソッドのコードの続き。
前回は座標軸回転(rotateAxis)についてでした。 残りの移動系メソッドの話に進みます。
平行移動(translate)
移動系メソッドはすべて、基本的な流れは同じもので以下のとおりです。
- 新規に Matrix3D オブジェクトを生成
- その新規行列の当該成分に対して当該値を代入
- 現在の行列との合成
となると、平行移動も座標軸回転(rotateAxis)を踏襲して以下のようなコードで良さそうなもんです。
/** * 平行移動 * | 1 0 0 dx | * | 0 1 0 dy | * | 0 0 1 dz | * | 0 0 0 1 | */ public function translate( dx:Number, dy:Number, dz:Number ):void { var mat:Matrix3D = new Matrix3D(); mat.tx = dx; mat.ty = dy; mat.tz = dz; concat( mat ); }
しかし、平行移動(translate)と拡大縮小(scale)は、このようなコーディングはしません。
その理由は concat() です。
concat() は前々回のコードを見ていただくと分かるように、掛け算の数がやたら多いです。 掛け算というのは処理に時間がかかるとのこと。 ならばなるべく掛け算は使わないようなコーディングを心掛けたいもの。 つまり三次元変換行列でいうと、concat() の使用をできるだけ減らすということですね。
ところで行列には単位行列というものがあります。
正方行列(列の要素数と行の要素数が同じ行列)において、左上から右下に向かう対角線上の値が1でそれ以外は0という形の行列です。
三次元変換行列においては4×4の正方行列を使用するので、単位行列は以下のようになります。
| 1 0 0 0 | | 0 1 0 0 | | 0 0 1 0 | | 0 0 0 1 |
ここに二つの正方行列があるとします。 ひとつは成分が何でも良い任意の正方行列(以下"a"とします)。 もうひとつは行列aと同じ列数・行数の単位行列(以下"I"とします)。
この二つの項の乗算は交換法則を満たします。そして積は行列aと同じになります。
concat() のときに書きましたが、普通、行列の乗算は交換法則が成立しません。その例外が単位行列なわけです。
a * I = I * a = a
ようするに実数乗算における1ですね、単位行列というのは。
ここで平行移動の行列と単位行列を見比べてみてください。
単位行列 平行移動 | 1 0 0 0 | | 1 0 0 dx | | 0 1 0 0 | | 0 1 0 dy | | 0 0 1 0 | | 0 0 1 dz | | 0 0 0 1 | | 0 0 0 1 |
両者の構造はほぼ同じです。
とすると、平行移動を反映させる行列と行列aとの乗算の結果は、行列aとそれほどかけ離れたものにはならないことが予想できます。
実際に掛け算をおこない、concat() をトレースしてみましょう。
| na nb nc ntx | | 1 0 0 dx | | a b c tx | | nd ne nf nty | = | 0 1 0 dy | * | d e f ty | | ng nh ni ntz | | 0 0 1 dz | | g h i tz | | 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 | ↓ na = 1*a + 0*d + 0*g + dx*0; nb = 1*b + 0*e + 0*h + dx*0; nc = 1*c + 0*f + 0*i + dx*0; ntx = 1*tx + 0*ty + 0*tz + dx*1; nd = 0*a + 1*d + 0*g + dy*0; ne = 0*b + 1*e + 0*h + dy*0; nf = 0*c + 1*h + 0*i + dy*0; nty = 0*tx + 1*ty + 0*tz + dy*1; ng = 0*a + 0*d + 1*g + dz*0; nh = 0*b + 0*e + 1*h + dz*0; ni = 0*c + 0*f + 1*i + dz*0; ntz = 0*tx + 0*ty + 1*tz + dz*1; ↓ na = a; nb = b; nc = c; ntx = tx + dx; nd = d; ne = e; nf = f; nty = ty + dy; ng = g; nh = h; ni = i; ntz = tz + dz;
結果、成分 tx、ty、tz はそれぞれの移動量をプラスするだけ、それ以外の成分は変更なし、となりました。
それを踏まえると平行移動(translate)のコードは以下でオケ。
public function translate( dx:Number, dy:Number, dz:Number ):void { _tx += dx; _ty += dy; _tz += dz; }
ああっ! なんてスッキリ!
続く。