C++で5年ほど前に作成した3Dソフトボディ物理エンジン(partix)が埃をかぶっていてもったいなかったので、emscriptenでJavaScriptに移植してみました。形状を球などのプリミティブでなく、メッシュで割と正しい形に表現できるエンジンです。
成果物はこちら。ブラウザでそのまま転がして遊べます。よかったら、何体まで60fpsを維持できたか教えてください。
元々のプロダクトはこの動画にあるものです。
ちょっとした体験記です。
emscriptenのインストール
よく覚えてませんが、だいたいこんな感じだったと思います。私は最初ubuntu12.04のコンテナにインストールしようとして失敗しました。最新バージョンにアップグレードしたら大丈夫でした。
移植作業
言語
純粋なC++としては、全く何もイジる必要がない感じです(後述のバグっぽいものを除く)。
partixは標準ライブラリ以外に依存するものがないので、特に問題はありませんでした。
描画周り
emscriptenでは3D描画はOpenGL ES 2.0の流儀で書くことになっています。OpenGL ES 2.0の流儀で書いておけば、emscriptenがよしなにwebglに変換してくれます。
元々のコードがDirectX9の固定機能パイプラインで実装されていたので、まずOpenGL ES 2.0に移植するのが大変面倒でした。
OpenGL ES 2.0になおしてからは、びっくりするほど普通に動いた感じです。私はOpenGLに慣れてないのでそれなりに時間がかかりましたが、慣れてる人ならさほど問題無さそうです。
速度
上記のniconico動画にアップロードしたムービーを作った時は、確かCore2Duoで10体くらいしか出せなかったんですが、emscripten版では普通に9体くらいで60fpsを維持できたので大変驚きました。
といっても使ってるマシン違うんですが。過去のはC2D 2.4GHzくらい、emscripten版を実行したマシンはMacMiniの現行で一番安いヤツです。Corei5くらいだっけ?
これが驚いたことにコンパイルオプションで最適化してない状態の速度で、-O2をつけたら16体くらいまで出せました。
「同じ環境で調べろよ使えねーな」と言われそうですね。要望があれば調べます。
ちなみにGPUはスカスカでほとんどCPUで決まるアプリです。
C++とJavaScriptの連携
ここが参考になりました。マウス周りとテクスチャ周りはJSで書いて連携しています。
キーボードはglutでいけたので、マウスも実は必要なかったかも。
OpenGLはコンテキストが1つしかないので、普通にcanvasからglコンテキストを取得するコードを混ぜても特に問題ありませんでした。
ファイル
仮想ファイルシステムをリンク時にembedすることができます。このアプリでもテクスチャ以外のデータはそのようにして使っています。
デバッグ
デバッガがないし出力JSが馬鹿でかいし(13Mとかある)内容もほとんどアセンブラなのでかなり厳しいです。SourceMapとかうまく設定すればいけるのかな?
ただprintfは普通に使えるので、デバッガに頼り切りの人でなければなんとかはなるでしょう。
バグ?
emspcriptenに、メンバ変数のないクラスを実体化するときにメソッドが消えて?意味不明な実行時エラーがでるっぽいバグがあるらしくて、ちょっとハマりました。最小ケースを作ってみたいですが、うまくいくかな?