図解でわかる！ARKitのtransform理解のための4×4行列の説明

先日[ARKitのための3D数学](https://qiita.com/k-boy/items/775633fe3fd6da9c5fb6)という記事を書きました。その中でも言及していますが、今記事では、transformを理解するために、**4*4行列だけ**にフォーカスして説明していこうと思います。

僕も最初はよくわかっていませんでした。しかし今では理解できていて、座標変換するときに4*4行列を使うことの便利さを痛感しています。

## 4*4行列とはなんなのか

<img src="https://camo.qiitausercontent.com/c5e05164e0acc786ef793c4c0ae4c070888b5dea/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3131313336362f39333233386630342d336333332d343364362d636566392d3839323366643162643132362e706e67">

行列です。
この行列をベクトルに掛けると、座標を変換することができます。

**こんなかんじの行列のイメージだけまずは覚えてください。**

## 3D座標系を理解しよう

![image](https://image.shutterstock.com/image-illustration/reference-system-threedimensional-space-cartesian-260nw-1125824975.jpg)

3D空間上にx軸とy軸とz軸があって、その空間上の点が`(x, y, z)`という座標系で表されることは中学高校の数学をやっていれば理解できるでしょう。

以下の図では、xがaで, yがbで, zがcで示される点Pを表しています。

![image2](http://electron9.phys.utk.edu/vectors/images/p20.gif)

しかし、**座標変換を考えるときに、この点だけを考えるのは得策ではありません。**

ベクトルで考えるのがオススメです。

## 点Pをベクトルで考える

点Pをベクトルで表現してみました。

![xyz.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/834fdb4a-2245-2d15-af60-a9d7541d7846.gif)

原点から点Pに伸びる矢印です。

点Pだけではベクトルを表現できません。なぜなら原点から伸びる矢印じゃなくて、別のところから矢印を伸ばすことで**別の大きさ、向きのベクトル**を作ることができるからです。

以下みたいな感じ。

![xyzのコピー2.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/2936b101-88da-a352-8189-4d7c86e25881.gif)

**ベクトルは点ではなく、向きと大きさを含んだ矢印です。**

## オブジェクトで考えてみよう

次に以下のようなポットを考えてみましょう。

<img src="https://camo.qiitausercontent.com/398fa5d0fcbdeab156f550f5319772069ed83749/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3131313336362f65656539316664372d633434632d333735632d323461372d6130303661343835643661662e6a706567" width=400>

ポットを囲む六面体は先ほど紹介したベクトルを使って考えることができます。

以下のイメージです。OとPが決まれば六面体が確定できるのでその六面体の中にある**ポットの向きと大きさを定義すること**ができます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/38dfab4e-c6e8-cb41-d77f-42d701e4d649.jpeg" width=400>

では、4*4行列の話に戻ります。

## ここで4*4行列をみてみよう

<img src="https://camo.qiitausercontent.com/c5e05164e0acc786ef793c4c0ae4c070888b5dea/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3131313336362f39333233386630342d336333332d343364362d636566392d3839323366643162643132362e706e67">

ポットのベクトルの**向き（回転）**と**大きさ(拡大縮小)**は、この行列の赤で囲まれた部分を使って変換できます。

### 拡大縮小

|オリジナル|大きさ２倍|
|:-:|:-:|
|<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/d487f94e-60c7-a487-7d1b-72f5c621b42f.jpeg" width=200>|<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/83ddb3a6-4ace-9027-77cf-1cc4218e0961.jpeg" width=400>|

<img width="264" alt="スクリーンショット 2018-10-31 22.00.46のコピー.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/02c4a2cc-7e57-c681-bb92-91ebd50998f6.png">

ベクトルが拡大しましたね。

この左にある4*4行列が、２倍の拡大を表す4*4行列です。

### 回転

次に、このポットをz軸を中心に30度回転させるケースを考えてみましょう。

<img src="https://qiita-image-store.s3.amazonaws.com/0/111366/b779a0d8-98b2-0809-707e-eebd2bf01386.jpeg" width=300>

<img width="682" alt="スクリーンショット 2018-11-01 8.56.06のコピー.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/7800ffff-9c35-2f35-a3ae-f56c436d81a8.png">

ベクトルが回転しましたね。

x、y、z軸を中心に回転する時の行列は決まっているので、わからなければ都度確認すればいいと思います。https://ja.wikipedia.org/wiki/%E5%9B%9E%E8%BB%A2%E8%A1%8C%E5%88%97

そして、iOS開発においてはSceneKitのAPIで作れるので心配はいりません。ARCore Sceneformでも作れるし、c++にもあります。覚える必要はありません。

### 移動

ここまででお気づきになられた方もいるかもしれませんが、拡大縮小と回転は、原点を移動しません。

つまり、例のポッドの位置は変換前後で変わっていません。**ここで、4*4行列の一番右の列が登場します。**

<img src="https://camo.qiitausercontent.com/c5e05164e0acc786ef793c4c0ae4c070888b5dea/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3131313336362f39333233386630342d336333332d343364362d636566392d3839323366643162643132362e706e67">

青く囲まれている平行移動の部分です。ここの要素が、移動の役割をします。

以下のようにΔで示された移動量がそのままx, y, zそれぞれにプラスされるのです。

<img width="309" alt="スクリーンショット 2018-11-01 9.19.56のコピー.png" src="https://qiita-image-store.s3.amazonaws.com/0/111366/a126bd11-5dab-bf8f-6568-2d7b9d15613a.png">

幾何学的に考えると、以下のようなイメージ。

![objectのコピー4.jpeg](https://qiita-image-store.s3.amazonaws.com/0/111366/35252eb3-47dc-185e-9a5d-5cf82d5440a6.jpeg)

大きさや向きは変えずに、原点だけを平行に移動しています。


### 投影

こちらの行列計算については複雑なので省略しますが、以下の行列の図の赤い部分の値の変更で表現できます。

<img src="https://camo.qiitausercontent.com/c5e05164e0acc786ef793c4c0ae4c070888b5dea/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3131313336362f39333233386630342d336333332d343364362d636566392d3839323366643162643132362e706e67" width=200>

## まとめ

最後にもう一度、4*4行列を見てみましょう。

<img src="https://camo.qiitausercontent.com/c5e05164e0acc786ef793c4c0ae4c070888b5dea/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3131313336362f39333233386630342d336333332d343364362d636566392d3839323366643162643132362e706e67">

この4*4行列の何が便利かというと、**回転と拡大縮小と(投影)と移動が１つで表現できること**です。この行列の中に、オブジェクトに与えたい座標変換の全てを詰め込むことができます。

また、これは掛け算して合成することもできるため、OからA、AからB、BからCと３つの座標変換があったとしても掛け算すれば0からCの変換行列を作ることができるのです。

また別記事で、行列の掛け算や、実際にARKitやARCoreでどのAPIの組み合わせをすればいいのか紹介したいなと思います。

## 関連記事

- [ARKitのための3D数学](https://qiita.com/k-boy/items/775633fe3fd6da9c5fb6)
- [SceneKitで行列を乗算する時の注意点](https://qiita.com/k-boy/items/40354da198b91619f5c3)