アフィン変換行列による3次元ベクトルの変換は少し簡略化できる

3次元ベクトルを行列で変換して再び3次元ベクトルとして扱うときに、アフィン変換行列ではこの変換作業を簡略化できます。通常は4x4行列とベクトルの積をとるために同次座標との相互変換が必要になりますが、アフィン変換であれば簡略化できます。

変換手順

3次元ベクトルを行列で変換して再び3次元ベクトルとして扱うときの変換手順についてです。

変換前のベクトルを(x,y,z)(x,y,z)、行列で変換後のベクトルを(x,y,z,w)(x',y',z',w')、最終的に求めるベクトルを(x,y,z)(x'',y'',z'')とすると、次の手順になります。

  1. 3次元ベクトルを同時座標に変換(通常通り)

    • (xyz1)=(xyz)\begin{pmatrix}x\\y\\z\\1\end{pmatrix} = \begin{pmatrix}x\\y\\z\end{pmatrix}
  2. 同次座標に変換したベクトルとアフィン変換行列MMの積を計算(ww' 要素の値は計算不要)

    • (xyzw)=M(xyz1)\begin{pmatrix}x'\\y'\\z'\\w'\end{pmatrix} = M \cdot \begin{pmatrix}x\\y\\z\\1\end{pmatrix}
  3. 変換結果の要素x,y,zx,y,zをそのまま結果の3次元ベクトルとして扱う(ww' 要素は考慮不要)

    • (xyz)=(xyz)\begin{pmatrix}x''\\y''\\z''\end{pmatrix} = \begin{pmatrix}x'\\y'\\z'\end{pmatrix}

つまり、同時座標から3次元座標に変換するときにww'要素で割る必要がないということです。

数式で書くと次のようになります。

通常の変換が

(xyzw)=(M11M12M13M14M21M22M23M24M31M32M33M34M41M42M43M44)(xyz1),(xyz)=(xwywzw) (w0)\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 \\ 1\end{pmatrix} , \\ \begin{pmatrix}x'' \\ y'' \\ z''\end{pmatrix} = \begin{pmatrix}\frac{x'}{w'} \\ \frac{y'}{w'} \\ \frac{z'}{w'}\end{pmatrix} ~ (w' \ne 0)

対して、アフィン変換であれば

(xyz1)=(M11M12M13M14M21M22M23M24M31M32M33M340001)(xyz1),(xyz)=(xyz)\begin{pmatrix}x' \\ y' \\ z' \\ 1\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} \\ 0 & 0 & 0 & 1 \\ \end{pmatrix} \begin{pmatrix}x \\ y \\ z \\ 1\end{pmatrix} , \\ \begin{pmatrix}x'' \\ y'' \\ z''\end{pmatrix} = \begin{pmatrix}x' \\ y' \\ z'\end{pmatrix}

のように計算できます。

行程について個別にもう少し掘り下げた説明は次の記事に書いています。

エンジンやライブラリの対応

エンジンやライブラリによっては、専用の関数が用意されていることがあります。 この記事が使い分けの参考になればと思います。

例えば、ゲームエンジンのUnityには、汎用版である Matrix4x4.MultiplyPoint 関数と、アフィン変換を前提にした高速版である Matrix4x4.MultiplyPoint3x4 関数が存在します。

理屈

アフィン変換行列の第4行は定数です:

(adgjbehkcfil0001)\begin{pmatrix} a & d & g & j \\ b & e & h & k \\ c & f & i & l \\ 0 & 0 & 0 & 1 \end{pmatrix}

これは、任意のアフィン変換行列同士を合成しても変わりません:

(adgjbehkcfil0001)(mpsvnqtworux0001)=(am+dn+goap+dq+gras+dt+guav+dw+gx+jbm+en+hobp+eq+hrbs+et+hubv+ew+hx+kcm+fn+iocp+fq+ircs+ft+iucv+fw+ix+l0001)\begin{pmatrix} a & d & g & j \\ b & e & h & k \\ c & f & i & l \\ 0 & 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} m & p & s & v \\ n & q & t & w \\ o & r & u & x \\ 0 & 0 & 0 & 1 \end{pmatrix} = \begin{pmatrix} am + dn + go & ap + dq + gr & as + dt + gu & av + dw + gx + j \\ bm + en + ho & bp + eq + hr & bs + et + hu & bv + ew + hx + k \\ cm + fn + io & cp + fq + ir & cs + ft + iu & cv + fw + ix + l \\ 0 & 0 & 0 & 1 \end{pmatrix}

このような行列でベクトルを変換するとき、変換結果の ww' の値は変換前の ww と同じになります:

(xyzw)=(adgjbehkcfil0001)(xyzw)=(ax+dy+gz+jwbx+ey+hz+kwcx+fy+iz+lww)\begin{pmatrix}x' \\ y' \\ z' \\ w'\end{pmatrix} = \begin{pmatrix} a & d & g & j \\ b & e & h & k \\ c & f & i & l \\ 0 & 0 & 0 & 1 \end{pmatrix} \begin{pmatrix}x \\ y \\ z \\ w\end{pmatrix} = \begin{pmatrix} ax + dy + gz + jw \\ bx + ey + hz + kw \\ cx + fy + iz + lw \\ w \end{pmatrix}

よって、ww 要素が 1 のベクトルを変換した結果の ww' 要素も 1 になるので、(結果の xx', yy', zz' 要素を 1 で割っても値は変わらず、) xx', yy', zz' 要素だけを考慮すればいいことが分かります。