虚無なXmasをARで彩る

# 初めに（追記）
今回製作した物の動作デモです。
長い上まとまりのない記事を読む前に、
デモを最初にご覧ください！なんと優しい :sob: 

[**こちら**](https://www.youtube.com/watch?v=w0A2_R3jbbo)をクリックするとYouTubeに飛びます。

# 誰

生徒です

# 挨拶

今年も残り僅か．2019年目前です．皆さん元気にお過ごしでしょうか :thinking: 僕は色々なことにに追われ，ゲッソリ元気ハツラツです :blush: :exclamation: 必死にアドカレ記事を書いて心臓バクバクです :sweat: 

今は新年の他にクリスマスも目前という訳でして，今回はクリスマスネタです（それしか思いつきませんでした）また，言い訳蒲しいのですが，個人的な用事や仕事等で時間が足りなかったので，今回はかなり妥協した開発になっています :cry: 不完全燃焼です :fire: 

さて，本日の献立です :yum: :fork_and_knife:

>
 - 序章 : アイデアと技術の紹介
>
 - 本論 : 実際に作ってみた
>
 - 終章 : 開発から得られた情報
>
 - おまけ

**開発したものだけを見たい方**は，序章は読み飛ばして貰ってOKです :exclamation:
本論は中身を知りたい方だけが読めばいいと思います :smile: 

# 序章 - アイデアと技術の紹介
今回は「クリスマス」というテーマを最初に設けました．
そこで僕は，**Webで動作するARコンテンツ**を考えつきました．

## アイデアの話
今回適当に20日を選び，そこから**「クリスマス近いじゃん、これしかない」**と決めた感じです．その御蔭で，テーマは速攻確定したので，アイデアをゆっくり考えました．

### 当初の予定
最初のアイデアは出先でスマホにちまちまメモしてました．
当初の予定は以下の通りでした．

>
・拡張現実イルミネーション
スマホ、PC両方で動作するもの
>
・フローイメージ
①植物を写す
>
②葉の部分を認識させる
>
③ARでイルミネーションを描画する
>
・技術的な部分
①Webカメラの起動
　・JavaScriptを用いる
>
②画像解析、認識
　・Pythonを使った機械学習
　・OpenCVとやらを用いる

スマホに入ってたメモをコピペしました．見てわかるのですが，サーバーを用意して，サーバー側で画像解析を行わせる予定でした．しかし，このアイデアは現実的にキツく(とにかく時間が無く)すぐに諦めて路線変更しました :cry: 

### 路線変更
何とかAR技術を(使い|覚え)たい思いがあったので，根本の拡張現実のアイデアは継承することにしました．この段階でARを扱うにあたって2つ問題点がありました．

>
* 慣れない言語，慣れない開発形態
* 未対応の機種が数多く存在する

自分が慣れない新しい環境での開発を成し遂げられるのかという問題と，多くの環境で動作させることが出来ない問題でした．しかし，この問題は「「「僕と`AR.js`の，運命的な出会い」」によって解決しました．

>
**AR.js** is 何 :thinking: 
* JavaScript製のマーカー認識型ARライブラリ

つまり
>
* 僕が一番慣れている言語**JavaScript**のライブラリ :v:
* **マーカー認識**を使うので，**殆どの環境で動く** :v: 

これで2つの問題が解決出来ました :v: :v:

### 新たなアイデア
僕はこの運命的な出会いを果たしたお陰で，アイデアを練り直す時間が与えられました．そこで考えていた物を紹介します．

#### その1
>
マーカー上にプレゼントボックスを表示させ，タップするとランダムでアイテムの出現するガチャ

文章の通りガチャが引けます，クリスマスガチャです．然し時間が足りず断念してしまいました．このアイデアは今すぐにでも実装したいアイデアですので，もしかしたら近日中に追加実装するかも知れません．

#### その2
>
マーカー上に冬をイメージした小さな世界を描く

今回採用したアイデアです．
いよいよクリスマス要素が薄れてきましたが気にしてはいけません :exclamation: :exclamation: :exclamation: 
少しでもクリスマス要素が欲しかったので，申し訳程度にプレゼントボックスを散りばめましたので，これで何の問題はないと思います(前言撤回)


## 技術紹介
ここからは今回活用した技術達の大まかな紹介です．

>
- ar.js
- three.js
- blender

以下ざっくり動作フローの紹介です．

>
1. 検出したいマーカーデータ(`*.patt`)を用意
2. `three.js`を用いて`blender`で作成したオブジェクトを読み込む．　
3. 読み込んだオブジェクトは`1.`にリンクしたグループに追加
4. Webカメラ起動しテクスチャとして描画
5. マーカー上のオブジェクトを描画

今回はカスタムマーカーをillustratorで作成し，マーカーに変換しました．
またオブジェクトはblederで自分でモデリング+UVマップをしました．
あとは云々して描画させるだけです．

# 本論 - 実際に作ってみた
さて，いよいよ僕が作ったものの紹介です．本当に不完全燃焼で色々ギミックを付け加えたかったのですが，締め切り直前まではこれが限界でした．以下のリンクを開くと実際の動作を確認できます．

* [**GitHub Repository**](https://github.com/JPNYKW/Xmas2018)
* [**GitHub Pages**](https://jpnykw.github.io/Xmas2018/)

マーカーは以下の画像です．
※画像をクリックするとGitHub Repository上の画像に飛びます．
[![**Marker Image**](https://github.com/JPNYKW/Xmas2018/blob/master/ar/marker.png?raw=true)](https://github.com/JPNYKW/Xmas2018/blob/master/ar/marker.png)

こちらを印刷あるいは画面に表示させ，カメラで写します．画面上の場合，光の反射などで認識しずらい場合があります．また紙面に印刷した際も，紙が湾曲し過ぎないように気をつけてください．また，マーカーを複数表示せると正常に動かない（はず）です．

マーカーを正常に認識すると，このようになるはずです．
![**Success Render**](https://i.snag.gy/TzLPvI.jpg)

冬の世界を小さく圧縮した簡単なアニメーションが再生されるはずです．イメージはスノードームです．(こちらを友人に見せたところスノードームと言う的を射た回答をもらったので使わせてもらってます :blush: )

---

ここからは技術紹介で書いた簡単なフローやその他仕組みに関してを細かく説明していきます．興味ないと言う方は読み飛ばして終章にを見ても構いません．

## 読み込んでいるjsファイルについて

まず，こちらが[**index.html**](https://github.com/JPNYKW/Xmas2018/blob/master/index.html)のファイルです．

```html:index.html
<script src="./js/three.min.js"></script>
<script src="./js/GLTFLoader.js"></script>
<script src="./js/ar.min.js"></script>
<script src="./js/main.js"></script>
```

これは上から順にこの様になっています．

* `three.js`の本体
* `three.js`でgLTFを読み込む為のscript
* `ar.js`の本体
* 自分で記述したscript

`three.js`と`ar.js`は良いかと思いますが，**「「`GLTFLoader.js` is 何 :thinking:」」**ですよね．これはBlenderのオブジェクトを読み込むために使っています．
詳しくは次の項目で説明します．

[**main.js**](https://github.com/JPNYKW/Xmas2018/blob/master/js/main.js)内にある，こちらのコードがオブジェクトの一つを読み込んでいる箇所です．

```javascript:main.js
let loader = new THREE.GLTFLoader();
loader.load('./ar/model/ground.glb', data => {
    let size = 0.2;
    let object = data.scene;
    object.scale.set(size, size, size);
    object.position.set(0, 0, 0);
    marker.add(object);
});
```

`loader`に対して`THREE.GLTFLoader()`というオブジェクトを生成し使っています．この`GLTFLoader`を呼び出すためには先ほどの`GLTFLoader.js`を読み込む必要がある訳ですね．

ちなみに当然ですが読み込む順番も大切です．`GLTFLoader.js`と`ar.js`は，共に`three.js`の機能に追加して動作するライブラリですので，必ず`three.js`より後に読み込まなければなりません．もしコンテンツを作成する際は些細なことですが気をつけましょう．(自分も少し引っかかったので)

## GLTF is 何 :thinking: 
さて一つ前でも触れましたがこの**GLTF**とは何者かについてです．前述の通りオブジェクトを読み込む物なのですが，少し`three.js`を齧ったことのある方ならこう思う方がいるかも知れません．

>
ちょっと待って！
その拡張子，`*.json`で良くない？

僕も前にthree.jsでblenderから読み込んだ記憶を元に，jsonで出力して読み込ませるんだろうな〜なんて思って，blenderにアドオンを追加しようとディレクトリを見て見ました．するとなんと言うことでしょう…

[**https://github.com/mrdoob/three.js/tree/dev/utils/exporters/blender**](https://github.com/mrdoob/three.js/tree/dev/utils/exporters/blender) より，

```md:README.md
The Blender exporter for the Three.js JSON format has been removed
```

と記されてます．どうやら前まで使用されていたthree.js用にjsonを書き出すアドオンが廃止されたようです．

しかし，有難いことに`three.js`は多くの3Dオブジェクトの拡張子に対応しています．そこで右往左往した結果`gLTF`と言う拡張子にたどり着きました(長いので省略)

ここで先程も載せた地面のオブジェクトを読み込むコードをもう一度見てみましょう．

```javascript:main.js
let loader = new THREE.GLTFLoader();
    loader.load('./ar/model/ground.glb', data => {
    let size = 0.2;
    let object = data.scene;
    object.scale.set(size, size, size);
    object.position.set(0, 0, 0);
    marker.add(object);
});
```

ここで一つ注意点があります．gLTFではSceneに含まれる全てのオブジェクトが含まれます．また，ローダーで読み込んだデータがSceneのデータではなく，Sceneのデータを含む一つのオブジェクトであることを忘れないようにして下さい．4行目にあるように，

```javascript:main.js
let object = data.scene;
```

読み込んだデータからSceneだけを取り出す必要があります．忘れるとエラーで怒られます．気をつけましょう :cry: そしてScene全体が出力されるため，複数のオブジェクトがあると全てが表示されます．例えば試行錯誤したモデルが散らばったblendファイルで書き出すと，その全てが凝縮されthree.jsで描画を行うと全てのオブジェクトが表示されます．

ですので今回僕は，家，木，等のオブジェクトをそれぞれ別々のファイルで制作し，一つのblendファイルには一つのオブジェクトのみが含まれる状態にして書き出しました．

またオブジェクトの大きさに関してですが，地面では

```javascript:main.js
let size = 0.2;
object.scale.set(size, size, size);
```

と記しています．この`0.2`というマジックナンバーは各オブジェクトによって違います．僕の場合はこの値は目利きで調度いい塩梅を調整しながらそれぞれの値を定めた感じです．そのままのサイズだと大きすぎて画面全体に広がったりしてしまうので，少し注意が必要です．

---
以下はgLTFを扱うにあたって基本的な部分です．導入から色の付け方までを記しておきます．

### gLTFアドオンどこ〜 :cry:
[**https://github.com/KhronosGroup/glTF-Blender-Exporter**](https://github.com/KhronosGroup/glTF-Blender-Exporter)
こちらのリンク先にあります．

[**https://github.com/KhronosGroup/glTF-Blender-Exporter/tree/master/scripts**](https://github.com/KhronosGroup/glTF-Blender-Exporter/tree/master/scripts)
こちらの`README.md`参考に導入すればOKです :wink:

### gLTFで色が付けられないよ～ :cry:
Blender側でMaterialをノードで作る必要があるのですが，ただ単にノードエディタで組めばいいというわけじゃないんです．これには`gltf metallic roughness`という特殊なノードが必要になります．

[**https://github.com/KhronosGroup/glTF-Blender-Exporter/tree/master/pbr_node**](https://github.com/KhronosGroup/glTF-Blender-Exporter/tree/master/pbr_node)こちらから`glTF2.blend`をダウンロードします．そして，色を付けたいオブジェクトファイルを開き，ファイルからリンクを選択します．

リンクを押すとファイルを選ぶ画面が表示されるので，先程ダウンロードした`glTF2.blend`を開き，`NodeTre`→`glTF Metallic Roughness`の順番で選択し，`ライブラリからリンク`を押します．

そうすると，ノードエディタ上で`gltf metallic roughness`が使用できるようになります．このノードの一番上の`BaseColor`に基本色(その名の通り)を入れると，オブジェクトに反映させることが出来ます．またこの状態で`gLTF`でエクスポートすると，無事に色付きで出力できます．やったね :exclamation: :exclamation:

因みに，テクスチャの場合は通常通りにUV展開し，テクスチャを作成した後に，画像テクスチャでテクスチャを読み込み`BaseColor`に接続すればテクスチャを反映させることが出来て，幸せになります :blush:

## カスタムマーカーの作成
次はカスタムマーカーを作る方法です．非常に簡単にできます．
まず最初に，任意の画像編集ソフトで任意の図形を描画し，`png`や`jpeg`等で保存します．

次に[**https://jeromeetienne.github.io/AR.js/three.js/examples/marker-training/examples/generator.html**](https://jeromeetienne.github.io/AR.js/three.js/examples/marker-training/examples/generator.html)にアクセスし，`UPLOAD`から作成した画像を読み込みます．

最後に`DOWNLOAD MARKER`でマーカーデータである`*.patt`ファイルをダウンロードし，`DOWNLOAD IMAGE`でマーカーの画像を保存します．これだけ．

#  終章 - 開発から得られた情報

今回の開発を通しての感想ですが，とりあえず動いたときの感動が大きかったです．
特にgLTF様様でBlenderから任意にオブジェクトをMaterialと共に出力できるのが大きいと感じました．

また細かな箇所ですが，似たような開発を行う方に向けての(当たり前の)アドバイスを幾つか置いておきます．

>
* マーカーは必ずアシンメトリーに

最初に作ったマーカーをシンメトリーにしてしまいました．
当然なのですが方向が一定になってしまうので気をつけましょう．

>
* オブジェクトのスケーリングを忘れずに

これは気をつけるというより慌てないでって感じですね．大丈夫だとは思いますがオブジェクトがおかしいのではなくサイズが巨大過ぎて表示がおかしい事があるのでという感じです．

>
* メモリクラッシュに気をつけて

これなんですが，当初雪を積もらせるために愚直に球体を削除せずに地面上で停止させたらメモリ落ちしたよっていう話です．オブジェクトを作りすぎると直面するかと思いますので，ぜひ気をつけて下さい．


# おまけ

AR.js練習中，MMDモデルを読み込んでみてと友人に頼まれて読み込んだ文香．
モデルはこちら[**https://ch.nicovideo.jp/sibainu/blomaga/ar1151600**](https://ch.nicovideo.jp/sibainu/blomaga/ar1151600)
![Fumika](https://i.snag.gy/PjQBof.jpg)

因みにこれが文香を表示させたら発狂した友人．
![Hakkyo](https://i.snag.gy/Vxd9Gp.jpg)

MMD表示できた祝にプロ生ちゃんを表示させてみた．
モデルはこちら[**https://3d.nicovideo.jp/works/td8608**](https://3d.nicovideo.jp/works/td8608)
![PuronamaChan](https://i.snag.gy/w1FpnJ.jpg)

木のモデリング中，木にかぶった雪だけを残してみたらエモくなったよって話．
![EmoiTree](https://i.snag.gy/EBy7Yr.jpg)

これはおうちのモデリング中に良い感じになったから撮ったよっていうスクショ．
![House](https://i.snag.gy/FGrnAD.jpg)

gLTFが読み込めた歴史的瞬間のスクショ．
![Rekisiteki](https://i.snag.gy/bCaU7D.jpg)

---

以上です．最後までありがとうございました :blush: