Babylon.js で WebGL プログラミングしたら、 Unity, MMD モデルの変換で苦労した話

WebGL ライブラリの [Babylon.js](http://www.babylonjs.com/) を使って、ゲームを作ってみました。
初音ミクを使った簡単な迷路ゲームです。クリアするとミクちゃんが勝利の舞い (※) を踊ってくれます。
※ 最後に詳述しますが、残念ながら端末によっては、ミクにアニメーションがつきません。

こちらからご覧になれます。
http://miku-miku-maze.herokuapp.com

ソースはこちら。
https://github.com/kimamula/miku-miku-maze

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/86045/0901602c-b3b6-0439-e844-2c508bee9863.png)


# TL;DR
書いてみたらダラダラ長くなってしまったので最初にまとめを。

* WebGL 用のモデルは、そのライブラリ向けに提供された素材か、チュートリアルなどを読んで自作したものを使うのがおすすめ
    * Unity や MMD から持ってくるのは、お手軽そうに思えて茨の道
    * ボーンが多くなるとアニメーションできる端末が限定されることにも注意
* Babylon.js は TypeScript なところが好印象。使い勝手もいい。

# きっかけ
最初こちらのブログを見て、 WebGL スマホでも動くようになったしきれいだなあ、なんか作ってみるかー、と軽はずみな気持ちで手をつけてみたのです。

* [生WebGL入門:初音ミクの美麗3Dモデルを表示する(前編)](http://nmi.jp/archives/582)

Unity や MMD のフリーで使える素材は簡単に手に入るので、ちゃちゃっと WebGL に使える形式に変換してやろうと。
あとは JS のイケてる WebGL ライブラリでちょちょいと動かしてやれば、すぐ完成するだろうと。

しかしその目論見が甘かった。
甘々でした。

# Unity や MMD のモデルの変換が一筋縄ではいかなかった
WebGL のライブラリは、それぞれ 3D モデルの独自フォーマットを持っています。

Web 上で 3D モデルを作成して、そのフォーマットのファイルを出力するツールなども提供されていますが、
（たとえば、 Three.js なら http://threejs.org/editor/ )
複雑なモデルを使いたい場合、モデリングは [Blender](http://www.blender.org/) などの 3DCG ソフトウェアで行い、そこから export するのが一般的なようです。

Unity や MMD のモデルを使いたい場合どうするかというと、一度 Blender に import してから、
さらに Blender 上で使用する WebGL ライブラリのフォーマットに変換 (export) することになります。

要は二段階のフォーマット変換を経るわけですが、その過程でモデリングがぐっちゃぐっちゃになったりするんですね。
以下は一例ですが、まず Blender に import した時点でたいていどこかしらおかしいんですよ。

* [ニコニ立体ちゃんを Blender に import した例](http://qiita.com/daxanya1/items/5a69c2b149ba08081322#%E3%81%AA%E3%81%9C%E3%81%8B%E8%88%8C%E3%81%8C%E5%87%BA%E3%81%A6%E3%82%8B%E3%81%AE%E3%81%A7%E5%BC%95%E3%81%A3%E8%BE%BC%E3%82%81%E3%82%8B)

こういうおかしなことになったやつを、どうにかこうにかいじくって、 Blerder 上ではまともに見えるようにした上で、
いざ WebGL ライブラリ用に export するわけですが、案の定、全然きれいに表示されないのですよ。
特にアニメーション。（動かさないならわりと大丈夫）

こうなるともう、どのタイミングで、何が原因で、表示がおかしくなったのか、皆目見当がつかず、お手上げ状態になります。
で、いろいろ試行錯誤したうえで、なんとか WebGL で正常に表示できたのが、以下の組み合わせでした。

* モデル: [Tda 式 Append ミク](http://dic.nicovideo.jp/a/tda%E5%BC%8Fappend%E3%83%9F%E3%82%AF)
* WebGL ライブラリ: Babylon.js

なお、 Blender への import にはこちらのツールを利用しました。

* https://github.com/sugiany/blender_mmd_tools

Blender から Babylon.js 用フォーマットへの export は、Babylon.js が提供しているツールを利用しました。

* http://blogs.msdn.com/b/eternalcoding/archive/2013/06/28/babylon-js-how-to-load-a-babylon-file-produced-with-blender.aspx

最初は、モデルは Unity ちゃんを使おうとしていたのです (声もついてるから) 。
ライブラリは、 Three.js でいこうと思っていたのです (一番メジャーっぽいから) 。
でも無理でした。

これから WebGL でちゃちゃっと何か作ってみようと考えている人には、 Unity や MMD からのモデルの流用はおすすめしません。
使用するライブラリ向けに提供されている素材や、チュートリアルで簡単に作れるものを使ったほうがいいです。
あまり本質的でないことに時間を取られることになるので。

# Babylon.js について
MS の中の人が開発にかかわっているようで、 IE のプロモーション的なものにも利用されています。

* [米Microsoft、「Assassin's Creed Pirates」ブラウザ版を無料公開](http://news.mynavi.jp/news/2014/05/20/293/)

私自身、 WebGL ライブラリを利用したのは今回が初めてなので、他と比較してどう、ということは言えないのですが、
個人的に好印象だったのが、 TypeScript を使って開発されていること。
まあ MS がからんでいるので当然といえば当然か。
リポジトリに同梱されている .d.ts ファイルを使って、型に守られた開発ができます。
(でもこの .d.ts ファイル、 npm install しても落ちてこないから、わざわざ取りに行かないといけないんですよね。なんでだろう。。)

使い勝手的にも、特にはまりどころはなく、すらすら書けました。

Babylon.js 関係ないですが、迷路の作成ロジックは下記の記事を参考にさせていただきました。

* [JavaScriptで迷路生成してみたよ](http://blog.xlune.com/2008/07/javascript_1.html)

# 最後の落とし穴
PC で動作確認して、うまく動いている。
では、スマホ (わりと新しめの Android/Chrome) で見てみようと、つないでみると、ミクが表示されません！

コンソールにはこんなエラーが。

```
BJS - [20:58:48]: Unable to compile effect: default
```

調べてみると、ブラウザの Max Vertex Uniform Vectors という値が低いことが原因のようです。
この値は、[こちら](https://www.browserleaks.com/webgl)のサイトに行くと簡単に調べられますが、
この値によって、 WebGL で利用可能なボーンの数が決められているそうです (なので Babylon.js 特有のエラーではないはず) 。

私の PC の chrome だと 1024, Android の Chrome だと 256 (ついでに iPad mini2 の Safari だと 128) でした。
一方、使っていた初音ミクのモデルのボーンの数は 234。

Android なら表示できそうに思えますが、ここで使われるボーンは uniform mat4 という 4 次元行列で表現されるもので、
Vertex Uniform Vectors は この 4 倍の値 (= 936) が必要なようです。

これも Unity や MMD からモデルを持ってきた弊害と言えそうです。
つまり、 Unity や MMD はそもそもブラウザの WebGL エンジンで動かすことを想定していないので、
たくさんのボーンを使ってリッチに作られてしまっている。
おそらく、最初から WebGL 向けに提供されているモデルであれば、ここまでボーンが多いことはないでしょう。

モバイルブラウザでも動くよう、ボーンを削ろうともしてみたのですが、そうするとアニメーションにも大幅な修正が必要になりそうで、
そこまではやりたくなかったのであきらめました。
結局、 Max Vertex Uniform Vectors が低い端末向けには、ボーンがない、したがってアニメーションもなく静止した状態の初音ミクを表示するようにしました。
悲しい。