読者です 読者をやめる 読者になる 読者になる

平行移動だって変換行列で

以前、幾何計算はベクトルで考えるときれいにプログラミングできるというコツを書きました
その続編として、図形のズームや回転、移動があるときには、ベクトルは必須ですよという話。

拡大縮小と回転には変換行列、これは習いましたね?

これは高校の代数幾何学で習ったはずです。座標をベクトルで表せば、特定の行列をかけるだけで拡大縮小と回転ができること。
横にx倍、縦にy倍のズームは\left(  \begin{array}{ccc}   x & 0  \\ 0 & y \end{array}\right)で、
原点を中心にθ度の回転は\left(  \begin{array}{ccc}   \cos \theta & -\sin \theta  \\ \sin \theta & \cos \theta \end{array}\right)です。

試しにやってみましょう。(10,10)を横に2倍、縦に0.5倍でズームすると
\left(  \begin{array}{ccc}   2 & 0  \\ 0 & 0.5 \end{array}\right)\left(  \begin{array}{ccc}   10  \\ 10 \end{array}\right)=\left(  \begin{array}{ccc}   20  \\ 5 \end{array}\right)
(10,10)を90°回転させると
\left(  \begin{array}{ccc}   0 & 1  \\ -1 & 0 \end{array}\right)\left(  \begin{array}{ccc}   10  \\ 10 \end{array}\right)=\left(  \begin{array}{ccc}   -10  \\ 10 \end{array}\right)

行列による座標変換のいいところは、変換行列同士を掛け合わせてしまうことができることです。何段階かの変換も、その行列を掛け合わせてたった一つの行列にできるので、記述も簡潔になるしなにより計算が早い。不可逆な変換でなければ、逆行列を求めることで逆変換も簡単に記述できます。

でも、回転とズームだけではたいした変換はできませんね。やはり水平移動がないと…… 水平移動は、無理なのかな?

余分な一次元が、水平移動を可能にする

2次元のベクトルに2×2行列を掛けるだけの変換では、水平移動を記述することはできません。が、余分な一次元を加えることで、簡単にそれが実現できてしまうのです。
余分な一次元ってなに?
それは、座標(a,b)をこう書くことです――(a,b,1)。
ダミーの次元を付け加えて、値を1としておく。これだけです。座標が3次元表示になるから、変換行列は3×3になりますね。
ズームと回転の変換行列は、こうなります。
\left(  \begin{array}{ccc}   x & 0 & 0  \\ 0 & y & 0 \\ 0 & 0 & 1 \end{array}\right)\left(  \begin{array}{ccc}   a  \\ b \\ 1 \end{array}\right)=\left(  \begin{array}{ccc}   ax  \\ by \\ 1 \end{array}\right)
\left(  \begin{array}{ccc}   \cos \theta & -\sin \theta & 0 \\ \sin \theta & \cos \theta & 0 \\0&0&1\end{array}\right)\left(  \begin{array}{ccc}   a\\ b\\1\end{array}\right)=\left(  \begin{array}{ccc}   a\cos \theta -b\sin \theta \\ a \sin \theta + b \cos \theta \\ 1 \end{array} \right)
2×2のときの変換行列の右と下に0を詰め込んだだけですね。これで、ダミーの3次元表示を回転&ズームできます。

次に平行移動。ここで初めて、3×3行列の余った場所を使います。
\left(  \begin{array}{ccc}   1 & 0 & x  \\ 0 & 1 & y \\ 0 & 0 & 1 \end{array}\right)\left(  \begin{array}{ccc}   a  \\ b \\ 1 \end{array}\right)=\left(  \begin{array}{ccc}   a+x  \\ b+y \\ 1 \end{array}\right)
うわ、ほれぼれするくらい簡潔に移動が記述できましたね!

実は、頻用されています

ダミーの次元を加えるというやり方、初めて知った人にはかなりトリッキーなやり方に思えるかもしれません。でもこれは、図形を扱うシステムではわりとよく使われる技法です。
例えば、postscript……ひいてはPDFでは2次元図形の座標を3次元で表示して変換しています。Direct3Dでも、空間図形の座標は4次元表示。3次元の図形を移動するには4×4行列を使うんですね。

僕はこの技法を知る前にDirect3Dのことを習って、変換行列が4×4行列である理由は「そういうものなんだ」と教わりました。ひどい先生に出会ったものだと思います。