【Unity】ゲームにおける行列の勘所をまとめてみた

3Dゲームの計算では行列がよく出てきます。
が、行列について調べると用語や計算方法ばかり出てきて、いつのまにか目的を見失いがちです。(学校教育の害悪ですね。)

ゲームに使う部分だけであれば行列はそんなに難しくないのでこの記事でまとめてみます。

ゲームにおける行列の使われ方

行列自体はただのグリッド状の数字の羅列です。

f:id:halya_11:20190104232400p:plain

また、3D空間の座標はたとえば(1, -1, 2)のように、3次元のベクトルで表されます。
これは見方を変えれば1行×3列の行列としてみることができます。
(正確には4列として扱いますがこれは後程説明します)

f:id:halya_11:20180301191142p:plain

次に、ゲームではよく変換行列という行列が使われます。 これは例えば「X軸方向に2動かす」という情報が含まれた行列です。
これを先ほどの座標の行列(1, -1, 2)に掛け合わせることで、X軸方向に2動かした座標が得られます。

f:id:halya_11:20180301233325p:plain

このようにゲームでは座標を変換するために行列を使います。

平行移動行列を作ってみる

実際に座標を移動させるための行列を作って移動させてみます。 移動させるための行列は次のように作ることができます。

X軸方向にTx、Y軸方向にTy、Z軸方向にTz動かしたいとき、

f:id:halya_11:20180301190455g:plain

このあたりはこう作るものだと覚えておけばいいと思います。

それでは実際に数値を入れて試してみましょう。

一点注意点で、上の行列式を見ればわかるように、変換行列は4行×4列です。
行列の積は掛けられる側の列数と掛ける側の行数があっていなければいけないので、座標の4つ目の列に1を入れて4列の行列とします。

f:id:halya_11:20180301190418g:plain

行列を計算するとちゃんと移動できました。

いろんな変換行列を作る

このように変換行列は自分で作ることができるのですが、直接行列に値をいれて作る機会は僕はあまりないです。
UnityのMatrix4x4クラスを使うといろんな行列が簡単に作れるので、このやり方を紹介しておきます。

// 変換前の座標
var point = new Vector3(2, 0, 0);

// 移動値
var translate = new Vector3(1, 0, 0);
// 回転値
var quaternion = Quaternion.Euler(new Vector3(0, 90, 0));
// 拡大値
var scale = Vector3.one * 2;
// 行列を生成
var matrix = Matrix4x4.TRS(translate, quaternion, scale);

// 変換前の座標に行列をかける
// 結果は (1, 0, -4)
point = matrix.MultiplyPoint(point);

説明はコメントの通りです。
こんな感じで直観的に行列を作ることができます。

結果を見ると、スケール > 回転 > 移動 の順番で処理されていることがわかります。

座標変換行列から移動値を得る

上記のように、スケールや回転、移動情報の入った下記のような変換行列が得られます。

f:id:halya_11:20180302003806g:plain

この合成後の変換行列からもいろんな情報が得られます。
まず、変換行列から移動値を得るには4行目を見ます。
1,2,3列目がそれぞれx,y,z軸方向への移動値です。

f:id:halya_11:20180302004200p:plain:w250

座標変換行列からスケール値を得る

同じようにスケール値を得ることができます。
スケール値は各行の長さと等しくなります。

f:id:halya_11:20180302004602p:plain:w400

W値の意味とベクトルの変換

上で平行移動行列を作った時に、元の座標の4列目の値(W値)に1を入れました。
ここに1の代わりに0を入れると、変換行列のうち、平行移動の情報が適用されなくなるという性質が生まれます。

f:id:halya_11:20180302005122p:plain:w400

この性質を利用すると、変換行列はそのままベクトルの変換に使うことができます。 ベクトルは位置情報をもたず方向と長さの情報だけをもつため、平行移動行列を適用してはいけないのです。

よって、ベクトルを変換するときにはW値に0を入れることで変換することができます。

座標変換行列から変換後のXYZ軸の向きを表すベクトルを得る

さてこのベクトルの性質を使うと、座標変換行列から変換後の各軸の正方向を表すベクトルを簡単に得ることができます。

これは単純に、下図のように1〜3行目を3次元のベクトルにするだけです。

f:id:halya_11:20180302010136p:plain:w400

これは考えてみればシンプルで、変換前のX軸方向の単位ベクトル(1, 0, 0, 0)に変換行列を掛けると変換後のX軸方向が求められるというだけの話です。

f:id:halya_11:20180302010503g:plain

変換後の軸のベクトルから座標変換行列を作る

逆に、変換後の各軸の方向が分かっていれば、その座標空間に変換する行列が求められることになります。

f:id:halya_11:20180302011145p:plain:w400

これはノーマルマッピングなどで接空間の変換行列を求めるときなどに使われているのを見ます。

回転行列を転置すれば逆行列が得られる

直行行列を転置すると逆行列が得られます。
そして回転行列は直行行列です。

つまり、回転行列を転置すれば逆行列が得られます。
転置の処理負荷は比較的軽いので、使える場面では積極的に使っていきたい性質です。

参考

その39 知っていると便利?ワールド変換行列から情報を抜き出そう

natsutan.hatenablog.com