たのしいさんすう
数学ってなんの役に立つんスかねえ……。
そう思っていた時期が私にもありました
はい、楽しい算数のお時間です。
今回は画像がいっぱいあります☆
3DCGなどでは投影、移動、回転、拡縮などの操作を4x4の行列で表現していますが、あまり仕組みを理解せずに何となく使っていませんか?まあ、まさに私の事なのですが。
私はこの変形行列を、この記事の後半あたりに書いてある「真実」に気づくまで全く理解せずに使っていたんですよね(しかもかなり最近まで)。
私と同じように、この「真実」に気が付いた瞬間「ああ、そういうことだったのか!!」とショックを受ける方が他にもいるかもしれませんので、私目線での変形行列解説をしたいと思います。
変形行列とは、ある点を別の点に変換するものです。
この「変形」を「行列」で表すと非常にうまく表現できるので、ある点からある点に座標を変換するという操作は行列。
行列Tに点Aを流し込むと点Bが出てくる、という事を
B = T * A
のように表現します。
例えば3点 A1, A2, A3 から成る三角形に、とある変形Tを施した結果どうなるか?を知りたければ
B1 = T * A1
B2 = T * A2
B3 = T * A3
を計算してやれば、変形後の三角形の各点 B1 B2 B3 が得られます。
ここでいう三角形とは、3DCGで言えばそのままポリゴンの事です。
ゲームの世界における三角形が画面上ではどのように映るのか?という「変形」を行列Tで表現してやれば、ワールド内の全ポリゴンの頂点座標に対して同じ行列Tを当てはめて、画面上での座標を得ることができます。
話を簡単にするために、まずは x 座標だけで考えてみます。
変換前の座標を Xin として、変換後の座標を Xout とした時
<LaTeX>
Xout = a Xin
</LaTeX>
が基本の式になります。
「Xin を a 倍すれば Xout になるよ」ってことです。
a が 1 より大きければ拡大、 a が 1 なら等倍、 a が 1 未満なら縮小ですね。
a がマイナスの値になると今度は左右反転します。
ところで、上の式は x しか使っていないので Yin (変換前の y) や Zin (変換前の z) がどんな値であっても Xout (変換後の x) には影響しませんでした。
もし Yin や Zin の値が Xout に影響するなら
<LaTeX>
Xout = a Xin + b Yin + c Zin
</LaTeX>
という式にします。
変換前の x, y, z それぞれの値が、変換後の Xin にどれだけ影響するかという値を a b c に入れます。
例えば
<LaTeX>
Xout = 1 Xin + 1 Yin + 0 Zin
</LaTeX>
のようにすると、Xin だけでなく Yin が大きくなればなるほど Xout も大きくなります。
Xinが大きくなるほど(変換前の点が右にあるほど)、それに加えて Yin が大きくなるほど(変換前の点が上にあるほど)、Xout が大きくなります(変換後の座標が右にずれていく)。
Yin = 0の高さを境にして、それより高いところにあるモノほど右にずれていき、低いところにあるものほど左にずれますので、変換前に |||| のようになっていたものは //// のように歪むことになります(剪断変形)。
では全体を左右にずらすには?
座標を左右にずらす(平行移動)、という操作は x に「移動量」を加えるのと同じです。
しかも、元の点がどこにあっても(Xin, Yin, Zin がどんな値でも) Xout には Xin に「移動量」を加えた値を入れたいのです。
つまり最終的に欲しい式は Xout = Xin + 移動量 ですから、以下のように定数項を追加します。
<LaTeX>
Xout = a Xin + b Yin + c Zin + d
</LaTeX>
例えば右に 2 だけ位置をずらす、という操作は x に 2 を加えるのと同じですから、次のようにします。
<LaTeX>
Xout = 1 Xin + 0 Yin + 0 Zin + 2
</LaTeX>
さて、これは x 座標を得るための式でした。実際には x だけでなく y も z も得る必要がありますから、x, y, z それぞれに対して同じように式を作ってやると
<LaTeX>
\begin{array}{rrrrrrrrr}
X_{out}&=&aX_{in}&+&bY_{in}&+&cZ_{in}&+&d \\
Y_{out}&=&eX_{in}&+&fY_{in}&+&gZ_{in}&+&h \\
Z_{out}&=&iX_{in}&+&jY_{in}&+&kZ_{in}&+&l \\
\end{array}
</LaTeX>
てな感じになります。この式で、a ~ l の値を適当に変えてやれば、拡大や平行移動などの変形ができるようになります。
ところで、上の式では d, h, l はただの定数になっていますが、これを定数ではなく「第4の座標 W の係数」であると考えると後々の計算が便利になりますので、(これは同次座標というのですが、それについては今度説明します)
とにかくこの第4の座標 W を入れてみることにします。
<LaTeX>
\begin{array}{rrrrrrrrr}
X_{out}&=&aX_{in}&+&bY_{in}&+&cZ_{in}&+&dW_{in} \\
Y_{out}&=&eX_{in}&+&fY_{in}&+&gZ_{in}&+&hW_{in} \\
Z_{out}&=&iX_{in}&+&jY_{in}&+&kZ_{in}&+&lW_{in} \\
\end{array}
</LaTeX>
この式を見れば分かる通り、とりあえず Win=1 としておけば今までの式と何ら変わることはありません。
さらに、Win という入力が増えたのでそれに対応する Wout という出力も得られるよう式を追加しておきます。
<LaTeX>
\begin{array}{rrrrrrrrr}
X_{out}&=&aX_{in}&+&bY_{in}&+&cZ_{in}&+&dW_{in} \\
Y_{out}&=&eX_{in}&+&fY_{in}&+&gZ_{in}&+&hW_{in} \\
Z_{out}&=&iX_{in}&+&jY_{in}&+&kZ_{in}&+&lW_{in} \\
W_{out}&=&mX_{in}&+&nY_{in}&+&oZ_{in}&+&pW_{in} \\
\end{array}
</LaTeX>
さて、ここからが一番重要なところです。
上の式から、係数の部分 a ~ p だけを抜き出してみます。
<LaTeX>
\begin{pmatrix}
a & b & c & d \\
e & f & g & h \\
i & j & k & l \\
m & n & o & p \\
\end{pmatrix}
</LaTeX>
これが変形行列です!!!!
これが 4x4 で並んでいる意味不明な数字の正体です!!
<LaTeX>
\begin{pmatrix}
X_{out} \\
Y_{out} \\
Z_{out} \\
W_{out} \\
\end{pmatrix}
=
\begin{pmatrix}
a & b & c & d \\
e & f & g & h \\
i & j & k & l \\
m & n & o & p \\
\end{pmatrix}
\begin{pmatrix}
X_{in} \\
Y_{in} \\
Z_{in} \\
W_{in} \\
\end{pmatrix}
</LaTeX>
てことです!
例えば入力座標を変更しないでそのまま出力するには単位行列
<LaTeX>
\begin{pmatrix}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \\
\end{pmatrix}
</LaTeX>
を使いますが、これは
<LaTeX>
\begin{array}{rrrrrrrrr}
X_{out}&=&1X_{in}&+&0Y_{in}&+&0Z_{in}&+&0W_{in} \\
Y_{out}&=&0X_{in}&+&1Y_{in}&+&0Z_{in}&+&0W_{in} \\
Z_{out}&=&0X_{in}&+&0Y_{in}&+&1Z_{in}&+&0W_{in} \\
W_{out}&=&0X_{in}&+&0Y_{in}&+&0Z_{in}&+&1W_{in} \\
\end{array}
</LaTeX>
と書くのと同じです。係数が 0 の部分は消えてしまいますから結局は
<LaTeX>
\begin{array}{rrrrrrrrr}
X_{out}&=&1X_{in}& & & & & & \\
Y_{out}&=& & &1Y_{in}& & & & \\
Z_{out}&=& & & & &1Z_{in}& & \\
W_{out}&=& & & & & & &1W_{in} \\
\end{array}
</LaTeX>
という部分だけが残り、
<LaTeX>
\begin{array}{rcl}
X_{out}&=&1X_{in} \\
Y_{out}&=&1Y_{in} \\
Z_{out}&=&1Z_{in} \\
W_{out}&=&1W_{in} \\
\end{array}
</LaTeX>
と同じになるという事が分かると思います。
私はこの「変形行列は変形式の係数部分だけを抜き出したモノである」と気づくまで数年かかりました(泣)。
<LaTeX>
X_{out}=aX_{in}+bY_{in}+cZ_{in}+dW_{in}
</LaTeX>
というのは4元1次方程式なんですね。
一応高校のときの数学で行列の基礎は習ったはずなのですが……。
(数Cってヤツですね。歳がバレるか?と思って今Wikiってみたら、数Cは数Bと数IIIに吸収されて2012年に行列と共に消えたらしいですね。……と思ったら、2022年に復活するらしいです)
その後、線形代数の授業では行列を使って連立1次方程式を解くテストを受けた覚えもあるのですが、当時は自分が何の計算をしているのか全く理解しないまま授業を受けていました。とりあえず先生の言う通りに数字をいじればマルが貰える、みたいな。
学校の授業って習ってる当時は全くありがたみが無いんですけど、どこでどう人生に関わってくるか分からないものですよね。まさかゲーム製作で行列に関わる事になろうとは。
「お前ら数学なんて学校卒業したらもう役に立たないと思ってるんだろ?実際役に立たないよ」と言って総ツッコミ食らっていた先生のこと思い出しました。
エロゲー作るのに役に立ってますよ先生……。(遠い目)
おまけ
今回の記事は数式を多用したので、久々に LaTeX にお世話になりました。ところでLaTeXって読めます?「らてふ」って読むみたいですよ。
以下のサイトで LaTeX のコマンドを入力すると、対応する画像を生成することができますので、興味があったら試してみて下さい。
https://texclip.marutank.net
http://hooktail.maxwell.jp/cgi-bin/mathimg.cgi
え? 画像?
やだなぁ、このLaTeXで作った数式の画像がいっぱいあったじゃないですかー。
(スミマセン)