elm-playground-3dのざっくり解説

# elm-playground-3dを使って作ったもの
[以前作った2Dゲーム](https://qiita.com/negiboudu/items/8d5a7278602598191c8c)を3Dにしました。
というと言い過ぎで、ゲームになっていませんが…。

[デモ](https://corocoro3d.netlify.com/) / [ソースコード](https://github.com/negiboudu/playground3d_test)

### 操作方法
マウスクリックでジャンプします。
マウスカーソルに追従してカメラが動きます。
スマホの場合はタップや長押しでそれと同じような操作になりました。
スマホ性能にもよると思いますが遅いです。

![スクリーンショット 2019-12-30 6.28.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118890/48f17e80-b65f-37d4-3299-78c5c181f99f.png)

# モジュールの概要
[@luca_mug](https://twitter.com/luca_mug)さんが作ったモジュール。（[github](https://github.com/lucamug/elm-playground-3d)）
elm-playgroundの3D版というわけではなく、3Dモデルを作り出して、3Dから2Dに変換し、elm-playgroundで扱えるようにするものです。

[@luca_mugさんによる解説記事](https://medium.com/@l.mugnaini/basic-3d-rendering-in-svg-elm-playground-3d-d1e8846cd06e)

# インストール
2019/12/30時点では、パッケージとして公開されてはいないので、[github](https://github.com/lucamug/elm-playground-3d/tree/master/src)から`Playground3d.elm`を入手して、自分のソースコードと同じsrcディレクトリに置いて使用します。
必要な依存パッケージがいくつかありますので、[elm.json](https://github.com/lucamug/elm-playground-3d/blob/master/elm.json)のdependenciesを参照して必要なパッケージをインストールしてください。
おそらくこれらをインストールすれば大丈夫です。

- evancz/elm-playground
- ianmackenzie/elm-3d-camera
- ianmackenzie/elm-geometry
- ianmackenzie/elm-units


# 基本の流れ

1. `cube`または`polygon3d`で3Dモデルを作り出す
1. `shape3dto2d`で3Dモデルをelm-playgroundのShape型に変換する
1. 変換の際には`camera`関数を使用する（`camera1〜4`はプリセットのようなもの）

# 関数
[elm-playground-3dのソースコード](https://github.com/lucamug/elm-playground-3d/blob/master/src/Playground3d.elm)冒頭を見ると、以下のものがexposingされています。

```elm:exposingされているもの
  Point2d
, Point3d
, camera
, camera1
, camera2
, camera3
, camera4
, cube
, fade3d
, group3d
, move3d
, polygon3d
, rotate3d
, scale3d
, shape3dto2d
, words3d
```

### Point2d, Point3d
直接扱うことはないようです。3Dから2Dに変換するときに間接的に使っているようでした。

### camera

```elm:シグニチャ
camera : EyePoint -> FocalPoint -> Point3d a -> Maybe (Point2d a)
```

`shape3dto2d`で使用します。
視点（EyePoint）と焦点（FocalPoint）を指定します。
この2つを指定することで返ってくる関数を`shape3dto2d`に渡すので、第3引数のPoint3d aを設定することはありませんでした。
camera1〜4はこの2つの位置の指定サンプル、プリセットのようなものです。

### cube

```elm:シグニチャ
cube : Playground.Color -> Playground.Color -> Playground.Color -> Playground.Number -> Shape3d
```

立方体を作り出します。
3つの色とサイズを指定します。
elm-playground-3dのソースコードを見てみたところ、polygon3dを6回呼び出して6面体を作っていました。

### polygon3d

```elm:シグニチャ
polygon3d : Playground.Color -> List Position -> Shape3d
```

色と点を指定して面を作ります。
これをgroup3dでくっつけて立体を作り出します。

### shape3dto2d

```elm:シグニチャ
shape3dto2d : (Point3d a -> Maybe (Point2d a)) -> Shape3d -> Playground.Shape
```

3Dをelm-playgroundで扱えるShape型に変換します。
3Dで色々操作したあと、必ず最後にこれを呼び出すことになります。

### その他の関数
fade3dなど、[elm-playground](https://package.elm-lang.org/packages/evancz/elm-playground/latest/Playground)にあった関数に3dをくっつけたような関数が多数ありますが、使い方も大体同じと考えて良さそうです。

# 座標

座標の考え方については、こちらの記事を参考にさせていただきました。
[右手系と左手系が違うと何が問題か](https://qiita.com/boiledorange73/items/b7369036a4dd1f24b866)

elm-playground-3dは「左手系」のようです。
ただし、矢印の向きは少し異なるようで、こうなっていました。
![xyz.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118890/69ea7041-9bff-9d8b-e40d-b97b3ebeffd4.png)

# 色、光源
光源までは扱えません。
3Dモデルの各面に自分で色を指定して、それっぽく色をつける必要があります。

# ハマったところ
### rotate3d
回転させたい方向の値を指定するのではなく、回転する際の軸となる座標軸を指定します。
私の場合はx方向に回転させたかったので、yの値を指定しました。

### move3d
1. cubeを作る
1. move3dで位置指定
1. rotate

キャラクターをコロコロする際に、こうしたらうまくいきませんでした。
回転の中心点はmove3dしても移動しないようで、move3dで移動した分だけ、振り回されるように回転してしまいました。
rotateしてからmove3dしたら期待通りにコロコロしてくれました。

# 感想
3Dモデルを作るのが大変だったり、自分で影っぽい色をつけたりするがゆえの違和感があったりはしますが、お手軽に3Dを扱えるのは楽しかったです。
3D部分の扱い方にさえ慣れてしまえば、あとはいつものelmプログラミングです。試してみてください〜。