行列とベクトルの積・行列と行列の積の説明

行列とベクトルの積・行列と行列の積について、3次元空間を扱う場合の基本的な知識について説明しています。

行列について

3次元空間を扱う場合、通常は平行移動を表現するために4x4行列を使用します。

ここでは、4x4行列を次のように表記します。

(M11M12M13M14M21M22M23M24M31M32M33M34M41M42M43M44)\begin{pmatrix} M_{11} & M_{12} & M_{13} & M_{14} \\ M_{21} & M_{22} & M_{23} & M_{24} \\ M_{31} & M_{32} & M_{33} & M_{34} \\ M_{41} & M_{42} & M_{43} & M_{44} \\ \end{pmatrix}

ベクトルについて

3次元空間を扱うベクトルは、単体で位置や方向を表すだけであれば3次元ベクトルでいいのですが、4x4行列との積を計算する場合は4次元ベクトルで同次座標系として扱います。

ここでは、4次元ベクトルを次のように表記します。

(xyzw)\begin{pmatrix}x \\ y \\ z \\ w\end{pmatrix}

行列とベクトルの積

ここでは、行列とベクトルの積を求める数式を次のように表記します。 (3Dプログラムで言うと、3次元空間上の頂点(同次座標)を行列で変換する処理にあたります。)

(xyzw)=(M11M12M13M14M21M22M23M24M31M32M33M34M41M42M43M44)(xyzw)\begin{pmatrix}x' \\ y' \\ z' \\ w'\end{pmatrix} = \begin{pmatrix} M_{11} & M_{12} & M_{13} & M_{14} \\ M_{21} & M_{22} & M_{23} & M_{24} \\ M_{31} & M_{32} & M_{33} & M_{34} \\ M_{41} & M_{42} & M_{43} & M_{44} \\ \end{pmatrix} \begin{pmatrix}x \\ y \\ z \\ w\end{pmatrix}

この計算は次のように行います。 (プログラミングするときはライブラリの関数を使うと思いますが、実装は次のような計算を行っています。)

(xyzw)=(M11x+M12y+M13z+M14wM21x+M22y+M23z+M24wM31x+M32y+M33z+M34wM41x+M42y+M43z+M44w)\begin{pmatrix}x' \\ y' \\ z' \\ w'\end{pmatrix} = \begin{pmatrix} M_{11}x + M_{12}y + M_{13}z + M_{14}w \\ M_{21}x + M_{22}y + M_{23}z + M_{24}w \\ M_{31}x + M_{32}y + M_{33}z + M_{34}w \\ M_{41}x + M_{42}y + M_{43}z + M_{44}w \\ \end{pmatrix}

上式を見ると、例えば、xx'の値を求めるときは、行列の1行目の要素に左から順にベクトルのxx,yy,zz,wwを掛けた値の合計を計算しています。 yy'であれば行列2行目の~(以下同文)という規則が見て取れます。

意味付けですが、少なくとも利用する立場としては、このように計算する決め事に対して、期待した結果が得られるように逆算して行列やベクトルを与えるという解釈でいいと思います。

行列と行列の積

ここでは、行列と行列の積を求める数式を次のように表記します。 (3Dプログラムで言うと、行列を掛け合わせて合成する処理にあたります。)

M=AB=(A11A12A13A14A21A22A23A24A31A32A33A34A41A42A43A44)(B11B12B13B14B21B22B23B24B31B32B33B34B41B42B43B44)M = A \cdot B \\ = \begin{pmatrix} A_{11} & A_{12} & A_{13} & A_{14} \\ A_{21} & A_{22} & A_{23} & A_{24} \\ A_{31} & A_{32} & A_{33} & A_{34} \\ A_{41} & A_{42} & A_{43} & A_{44} \\ \end{pmatrix} \begin{pmatrix} B_{11} & B_{12} & B_{13} & B_{14} \\ B_{21} & B_{22} & B_{23} & B_{24} \\ B_{31} & B_{32} & B_{33} & B_{34} \\ B_{41} & B_{42} & B_{43} & B_{44} \\ \end{pmatrix}

この計算は次のように行います。 (プログラミングするときはライブラリの関数を使うと思いますが、実装は次のような計算を行っています。)

M=(A11B11+A12B21+A13B31+A14B41A11B12+A12B22+A13B32+A14B42A11B13+A12B23+A13B33+A14B43A11B14+A12B24+A13B34+A14B44A21B11+A22B21+A23B31+A24B41A21B12+A22B22+A23B32+A24B42A21B13+A22B23+A23B33+A24B43A21B14+A22B24+A23B34+A24B44A31B11+A32B21+A33B31+A34B41A31B12+A32B22+A33B32+A34B42A31B13+A32B23+A33B33+A34B43A31B14+A32B24+A33B34+A34B44A41B11+A42B21+A43B31+A44B41A41B12+A42B22+A43B32+A44B42A41B13+A42B23+A43B33+A44B43A41B14+A42B24+A43B34+A44B44)M = {\footnotesize \begin{pmatrix} A_{11}B_{11} + A_{12}B_{21} + A_{13}B_{31} + A_{14}B_{41} & A_{11}B_{12} + A_{12}B_{22} + A_{13}B_{32} + A_{14}B_{42} & A_{11}B_{13} + A_{12}B_{23} + A_{13}B_{33} + A_{14}B_{43} & A_{11}B_{14} + A_{12}B_{24} + A_{13}B_{34} + A_{14}B_{44} \\ A_{21}B_{11} + A_{22}B_{21} + A_{23}B_{31} + A_{24}B_{41} & A_{21}B_{12} + A_{22}B_{22} + A_{23}B_{32} + A_{24}B_{42} & A_{21}B_{13} + A_{22}B_{23} + A_{23}B_{33} + A_{24}B_{43} & A_{21}B_{14} + A_{22}B_{24} + A_{23}B_{34} + A_{24}B_{44} \\ A_{31}B_{11} + A_{32}B_{21} + A_{33}B_{31} + A_{34}B_{41} & A_{31}B_{12} + A_{32}B_{22} + A_{33}B_{32} + A_{34}B_{42} & A_{31}B_{13} + A_{32}B_{23} + A_{33}B_{33} + A_{34}B_{43} & A_{31}B_{14} + A_{32}B_{24} + A_{33}B_{34} + A_{34}B_{44} \\ A_{41}B_{11} + A_{42}B_{21} + A_{43}B_{31} + A_{44}B_{41} & A_{41}B_{12} + A_{42}B_{22} + A_{43}B_{32} + A_{44}B_{42} & A_{41}B_{13} + A_{42}B_{23} + A_{43}B_{33} + A_{44}B_{43} & A_{41}B_{14} + A_{42}B_{24} + A_{43}B_{34} + A_{44}B_{44} \\ \end{pmatrix} }

上式を見ると、結果の行列MMの各要素ごとに、行列AAは行方向、行列BBは列方向に対になる要素を掛けた値の合計を計算しています。 AAのどの行、BBのどの列を使うかについては、計算する行列MMの要素の位置と同じ行および列を使います。

行列の積は二つの変換を合成することを意味します。 例えば、次の変換行列がある場合、

  • SS = 拡大縮小
  • RR = 回転
  • TT = 平行移動

次の計算において、

M=TRSM = T \cdot R \cdot S

計算結果MMは、拡大縮小(SS)、回転(RR)、平行移動(TT)を順番に適用した変換を表す行列になります。 列優先(行列の行優先と列優先についての説明参照)で表記しているので右の変換から適用されます。

これらの変換は適用する順番によって結果が変わりますが、行列の合成はこの順番も反映した結果になります。 そのため、順番が重要な変換も含めて、予め一つの行列に合成した上でまとめてベクトルを変換することができます。

余談になりますが、プログラムで利用する場合に、予め変換手順が決まっている物については行列の変換式の合成を事前に計算しておくことで、実行時に合成する負荷を減らすこともできます。 変数部分は実行時に計算が必要ではありますが、「3次元のアフィン変換の説明と定義」を見ても分かるように、変換によっては 0 と 1 が定数として結構現れるので実行時に総当たりで計算するよりも計算量が減らせる可能性があります。
現実的には労力に見合うのかというところが問題で、必要に迫られたときにやる感じだとは思いますが、こういう選択肢もあります。