変換手順
3次元ベクトルを行列で変換して再び3次元ベクトルとして扱うときの変換手順についてです。
変換前のベクトルを(x,y,z)、行列で変換後のベクトルを(x′,y′,z′,w′)、最終的に求めるベクトルを(x′′,y′′,z′′)とすると、次の手順になります。
3次元ベクトルを同時座標に変換(通常通り)
- ⎝⎜⎜⎛xyz1⎠⎟⎟⎞=⎝⎛xyz⎠⎞
同次座標に変換したベクトルとアフィン変換行列Mの積を計算(w′ 要素の値は計算不要)
- ⎝⎜⎜⎛x′y′z′w′⎠⎟⎟⎞=M⋅⎝⎜⎜⎛xyz1⎠⎟⎟⎞
変換結果の要素x,y,zをそのまま結果の3次元ベクトルとして扱う(w′ 要素は考慮不要)
- ⎝⎛x′′y′′z′′⎠⎞=⎝⎛x′y′z′⎠⎞
つまり、同時座標から3次元座標に変換するときにw′要素で割る必要がないということです。
数式で書くと次のようになります。
通常の変換が
⎝⎜⎜⎛x′y′z′w′⎠⎟⎟⎞=⎝⎜⎜⎛M11M21M31M41M12M22M32M42M13M23M33M43M14M24M34M44⎠⎟⎟⎞⎝⎜⎜⎛xyz1⎠⎟⎟⎞,⎝⎛x′′y′′z′′⎠⎞=⎝⎜⎛w′x′w′y′w′z′⎠⎟⎞ (w′=0)
対して、アフィン変換であれば
⎝⎜⎜⎛x′y′z′1⎠⎟⎟⎞=⎝⎜⎜⎛M11M21M310M12M22M320M13M23M330M14M24M341⎠⎟⎟⎞⎝⎜⎜⎛xyz1⎠⎟⎟⎞,⎝⎛x′′y′′z′′⎠⎞=⎝⎛x′y′z′⎠⎞
のように計算できます。
行程について個別にもう少し掘り下げた説明は次の記事に書いています。
アフィン変換とはどのような変換であるか
同次座標と通常の3次元座標の相互変換の方法
行列によるベクトルの変換方法(通常の方法)
エンジンやライブラリの対応
エンジンやライブラリによっては、専用の関数が用意されていることがあります。 この記事が使い分けの参考になればと思います。
例えば、ゲームエンジンのUnityには、汎用版である Matrix4x4.MultiplyPoint
関数と、アフィン変換を前提にした高速版である Matrix4x4.MultiplyPoint3x4
関数が存在します。
理屈
アフィン変換行列の第4行は定数です:
⎝⎜⎜⎛abc0def0ghi0jkl1⎠⎟⎟⎞これは、任意のアフィン変換行列同士を合成しても変わりません:
⎝⎜⎜⎛abc0def0ghi0jkl1⎠⎟⎟⎞⎝⎜⎜⎛mno0pqr0stu0vwx1⎠⎟⎟⎞=⎝⎜⎜⎛am+dn+gobm+en+hocm+fn+io0ap+dq+grbp+eq+hrcp+fq+ir0as+dt+gubs+et+hucs+ft+iu0av+dw+gx+jbv+ew+hx+kcv+fw+ix+l1⎠⎟⎟⎞このような行列でベクトルを変換するとき、変換結果の w′ の値は変換前の w と同じになります:
⎝⎜⎜⎛x′y′z′w′⎠⎟⎟⎞=⎝⎜⎜⎛abc0def0ghi0jkl1⎠⎟⎟⎞⎝⎜⎜⎛xyzw⎠⎟⎟⎞=⎝⎜⎜⎛ax+dy+gz+jwbx+ey+hz+kwcx+fy+iz+lww⎠⎟⎟⎞よって、w 要素が 1 のベクトルを変換した結果の w′ 要素も 1 になるので、(結果の x′, y′, z′ 要素を 1 で割っても値は変わらず、) x′, y′, z′ 要素だけを考慮すればいいことが分かります。