FlutterのMatrix4Dでtransformする方法

## 4D matrix とは

三次元を表現するために4*4の行列で表すものが4D matrixです。

なので、Matrix4クラスのコンストラクタは16個の引数を必要とします。

```dart
Matrix4(
  1, 0, 0, 0,
  0, 1, 0, 0,
  0, 0, 1, 0,
  0, 0, 0, 1,
)
```

上記のコードのように、右下がりの対角線上にある成分がすべて1で、残りの成分がすべて0であるものを identity matrix （単位行列）と呼びます。

identity matrix をtransformに与えても何も変更されません。

## 4D matrix を使ってScaleしてみる

こちらのデモはボタンを押すとx方向に2倍になります。

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="js,result" data-user="wim_web" data-slug-hash="VwvRRYm" data-preview="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="matrix4D scale">
  <span>See the Pen <a href="https://codepen.io/wim_web/pen/VwvRRYm">
  matrix4D scale</a> by うぃむ@謳って⤴謳って⤴雲の上ぇぇええ☁🥰 (<a href="https://codepen.io/wim_web">@wim_web</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

このように行列の値を変化させることでScaleしたりtranslateしたりできます。

しかし行列を直接いじるためには知識が必要になってしまうので（Rotationはsin, cosもでてくる）、簡単に扱えるようにMatrix4クラスにはファクトリが定義されています。


## いろんなファクトリ

### 大きさを変える

```dart
Matrix4.diagonal3Values(double x, double y, double z)
```

### 回転させる

```dart
Matrix4.rotationX(double radians)
Matrix4.rotationY(double radians)
Matrix4.rotationZ(double radians)
```

X, Y, Zは回転軸を表しています。

引数に渡すのは回転させたい角度ではなくてラジアンで指定します。

```
radian = angle * (pi / 180)
```

たとえば90度回転させたい場合は、

```
radian = 90 * (pi / 180) = 0.5 * pi
```

となります。

### ななめにする　ゆがめる

説明が難しいのでデモを見てください。

```dart
Matrix4.skewX(double alpha)
```

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="js,result" data-user="wim_web" data-slug-hash="YzyggoL" data-preview="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="skewX">
  <span>See the Pen <a href="https://codepen.io/wim_web/pen/YzyggoL">
  skewX</a> by うぃむ@謳って⤴謳って⤴雲の上ぇぇええ☁🥰 (<a href="https://codepen.io/wim_web">@wim_web</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

```dart
Matrix4.skewY(double beta)
```

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="js,result" data-user="wim_web" data-slug-hash="zYvbbgN" data-preview="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="skewY">
  <span>See the Pen <a href="https://codepen.io/wim_web/pen/zYvbbgN">
  skewY</a> by うぃむ@謳って⤴謳って⤴雲の上ぇぇええ☁🥰 (<a href="https://codepen.io/wim_web">@wim_web</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

それぞれに渡す引数の計算式はこちらです。

```
alpha = angle * (pi / 180)
beta = angle * (pi / 180)
```

ラジアンではなくタンジェントで計算されているので90度（0.5 * pi）は定義されません。（見えなくなる）

### 移動させる

```dart
Matrix4.translationValues(double x, double y, double z)
```

### 反対のMatrix4を作成する

```dart
Matrix4.inverted(Matrix4 other)
```

たとえばx方向に2倍させるMatrix4を引数に渡すと、x方向に1/2倍させるMatrix4が返ってきます。

以下のコードが同じになります。

```dart
Matrix4.diagonal3Values(0.5, 1, 1)

Matrix4.inverted(Matrix4.diagonal3Values(2, 1, 1))
```

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="js,result" data-user="wim_web" data-slug-hash="GRpeejO" data-preview="true" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="matrix4D inverted">
  <span>See the Pen <a href="https://codepen.io/wim_web/pen/GRpeejO">
  matrix4D inverted</a> by うぃむ@謳って⤴謳って⤴雲の上ぇぇええ☁🥰 (<a href="https://codepen.io/wim_web">@wim_web</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## メソッド

ファクトリはあくまで初期化なので、あるMatrix4クラスを変化させたいときはメソッドを使います。

だいたい似たような名前なのでなんとなくわかると思います。

こんな感じで使えます。

```dart
child: Transform(
  transform: Matrix4.identity()..rotateY(pi),
  child: Container(
    width: 100,
    height: 100,
    color: Colors.indigo[500],
  ),
),
```

## 参考

[Advanced Flutter: Matrix4 And Perspective Transformations](https://medium.com/flutter-community/advanced-flutter-matrix4-and-perspective-transformations-a79404a0d828)

[Matrix4 class](https://api.flutter.dev/flutter/vector_math_64/Matrix4-class.html)