VRM は Unity 専用じゃない!ブラウザで VRM 表示出来るものを作りました!

ザ・シードオンライン には、 glTF 規格の拡張である VR 利用想定のヒューマノイドモデル拡張の VRM 及び、 VirtualCast 上でインタラクティブなアイテムを自由に作成出来る VCI をアップロードすることが出来ます。

以前はそれらのファイルをブラウザ上で閲覧するのに、 Unity の WebGL ビルドを用いていました。

しかし、2019年5月現在の Unity の WebGL ビルド(と Web Assembly)は、数 MB のランタイムのダウンロードと、起動処理に数秒かかるなどの難点が存在していて、ネイティブ(JavaScript)実装に置き換えたいという要望が出ていました。一部端末で正常に表示出来ないという問題もあります。

そこで、私山岸の調査の結果、 babylon.js を採用し、自前で VRM/VCI を出来るだけ正しく porting するプロジェクトを稼働しました。

image.png
むーんちゃん! - 公開アイテム情報 - THE SEED ONLINE(α)

その成果物は virtual-cast/babylon-mtoon-material 及び virtual-cast/babylon-vrm-loader として MIT ライセンスで OSS 公開しています。誰でも利用可能ですし、コントリビュートも歓迎しています。

何故 babylon.js か?

既存の VRM ブラウザ実装では、 rdrgn/three-vrm が最も有力な OSS ライブラリだと思います。
これは three.js の examples 内にある GLTFLoader を拡張し、 BlendShape や SpringBone, MToonMaterial などの機能を移植したものとなっています。
three.js examples webgl_loader_gltf を見る通り、 PBR glTF モデルの読み込み速度やランタイム動作速度は申し分なく、「これで十分では」という見方が出来るかと思います。

また、 Google が公開した Web Custom Component による <model-viewer> タグ実装 も、内部では three.js を用いています。
現在の WebGL 業界を見ると、 three.js が圧倒的なシェアを誇っているのは言うまでもありません。
しかし、私は数年後を見据えて考えました。

What is babylon.js?

そもそも babylon.js という WebGL フレームワークを、ブラウザ界隈の人でも聞いたことがない場合が多いのではないかと思います。

babylon.js vs three.js
Google Trend: Babylon.js vs three.js

Google Trend を使って世界の人気度を見ても、 three.js とは比べ物にならないほど話題に上がっていないです。 Qiita の記事としても、 three.js は 400 記事近くあるのに対し、 Babylon.js は 14 記事…コミュニティの情報量としてはかなり心もとない数値です。

それでも選ぶ理由がいくつかありました。

Created by Microsoft

three.js と比べると人気度としては見劣りしますが、 WebGL 3D フレームワークの中では恐らく 2 位の知名度 であり、メインコントリビュータは Microsoft の人 です。

Windows 10 にデフォルトで入っている Paint 3D もネイティブで glTF をサポートしていますし、 Microsoft は glTF に強い意欲を持っている ことが伺えるため、そこに信頼できます。

glTF, PBR-based

babylon.js は、現在流行の glTF 規格及び物理ベースレンダリングを主要な要素として実装しています。

three.js は元々は普通の WebGL フレームワークで、追加として glTF や物理ベースレンダリングをサポート出来るようにしたので、その分無駄がある部分があります。

Created with TypeScript

Microsoft 製なので中身は全て TypeScript です。見やすい。型が嬉しい。

v4.0 Is Here!

Babylon.js 4.0 Is Here! – Babylon.js – Medium

つい先日、 babylon.js v4 のメジャーアップデートがありました。パフォーマンス改善や ES Module 対応など、力強い変更が行われています。

three.js とは異なり、 API の破壊的変更は基本的にメジャーバージョンアップでしか行われないため、 v4 の API を安心して活用することができます。

three.js の技術的負債とキャッチアップ難度

three.js は登場から長く経ち、技術的な負債が溜まってきているように見えます。

  • 独特なコードフォーマット(悪いわけではないですが、コミットしていくと考えると少し抵抗がある)
  • ソースコード自体が ECMAScript 5 相当で書きづらい、見づらい
    • tree shaking のための ES Module 対応は進んでいる様子
    • TypeScript で書かれていないということのデメリットは個人的には大きいです
  • 破壊的変更が多め
    • Migration Guide にある通り、各バージョンアップで互換性のない変更が入る
  • バージョンアップが大規模かつ頻繁
    • 様々なフォーマットやサンプルへの対応を全て 1 リポジトリに格納しているので、更新をトラックするのが本当に大変
    • Issue / Pull Requests の数がヤバい
    • (よく管理出来るなと感心)

自分が 3 年後に今書くスクリプトを保守しよう、と思った時、今と 3 年後でどれほどの違いが生まれるかを考えました。その時、 three.js は恐らく別の化け物に変わっていることでしょう。

それと比べ、 babylon.js はメジャーバージョンアップを除き破壊的変更がないので、保守コストはかなり低く抑えられると考えられます。

それでも内部でのパフォーマンス最適化や API 追加対応などは行われるので、最新技術をすぐに利用することは可能です。


これらを踏まえ、 3 年後は babylon.js がその勢いを増し、多くの WebGL 実装に babylon.js 、そして virtual-cast/babylon-vrm-loader を使ってくれるだろうという推測を元に、 babylon.js を採用しました。

何を作ったか

ここからはエンジニア的な話です。実装した感想を先に述べておくと、 「 babylon.js の API は結構分かりやすいし、公式ドキュメントがかなり充実しているので理解しやすい」 という感じです。 babylon.js にして正解だった気持ち。

babylon-mtoon-material

babylon-mtoon-material

2 カ月ほど専任でこの開発を行っていましたが、ほとんどは MToon マテリアル を Unity(ShaderLab) から WebGL(GLSL) に移植する作業に費やされました。

babylon.js では、追加の Material 実装として materialsLibrary が別パッケージで用意されています。このリファレンスを参考にして、新しいマテリアル(シェーダ)を作成することが出来ます。

OSS としてコミュニティが公開している Material 実装がなかったので、このあたりはかなり手探り状態でした。

babylon.js 自体がサポートする一般的な機能は、 StandardMaterial という実装にあります。具体的には下記のようなものです。

  • 複数個の光源
  • Multiview: VR 向け
  • LogarithmicDepth: 深度を log で表現
  • Fog: 遠くに行くと霧がかかったようになる
  • Bones in shader: ボーン操作を GPU で処理
  • MorphTargets in shader: モーフターゲット操作を GPU で処理
  • Shadow: メッシュから落ちる影
  • EffectFallback: 速度が足りない場合に自動で特定の機能を OFF にするフォールバック
  • Instances: GPU インスタンシング
  • ClipPlane: 見えないメッシュを表示しないようにする
  • AmbientColor: シーン全体の環境光
  • Alpha CutOff: 特定のアルファ値以下を全く表示しないようにする
  • Diffuse: 基本テクスチャカラー
  • Emissive: 自己発光テクスチャカラー
  • Bump: 凹凸表現のテクスチャ

他にも反射・屈折などの機能が搭載されていますが、 MToonMaterial は上記機能をそのまま引き継いで利用出来るように実装することにしました。ほとんどは StandardMaterial のコピペです。

Material の実装は、コンパイルしてシェーダを利用出来る状態にする isReady メソッドと、毎フレームシェーダに現在の値を渡す bind メソッドの二つがメインとなっているようです。それと追加して、 GLSL コードを用意する必要があります。

そこに、 MToon 独自のテクスチャやパラメータを設定出来るようにしました。

MToon はライティングのうち 「陰」 の計算を独自形式に変える必要があるので、 lightFragment.fx を置き換えるようにしました。

また、アウトラインを描画するため、 EdgesRendererOutlineRenderer 実装を参考にして、追加でレンダリングを実行出来るようにしています。

現在 VRM が出力する MToon のプロパティ情報は Unity のマテリアル機能に依存しているものもあるので、そのあたりを考慮して調整するのに時間がかかりました。

babylon-vrm-loader

babylon-vrm-loader

babylon.js で VRM / VCI ファイルを読み込めるようにするため、 glTFLoader の拡張を実装します。

といっても、 VRM / VCI ファイルの中身は glTF のままなので、拡張子として .vrm .vci を許可するように変更するだけですみました。超楽。

もちろん、それだけだと他の拡張機能が利用出来ないので、 VRMManager クラスをシーンの metadata として追加実装して、 BlendShape(表情) 機能と Unity Humanoid のボーン名からボーンを取得 する機能を実装しています。

しかし、 BlendShape 機能は glTF の MorphTarget というものを用いて実装されているのですが、 babylon.js 実装との相性の問題か、バグっています。

BlendShape(with MorphTarget) is broken · Issue #1 · virtual-cast/babylon-vrm-loader にまとめていますが、 MorphTarget を操作するとメッシュが破綻します。執筆現在でも原因が明らかになっていないので、もしどなたか原因がわかる方がいらっしゃいましたらご教授願いたいです。

tso-vrm-viewer

ザ・シードオンラインのリポジトリ上に、上記二つのパッケージを利用してビューアを表示する機能を設けています。

ボーンを取得して待機モーションをキーフレーム指定で再生したり、カメラを調整したり、アイコンを撮影できるなどの追加機能を実装しています。


今回の実装で、ブラウザ上で VRM を気軽に扱えるようになったので、ブラウザ VRM ゲームなどを実装していくことも可能になりました。私個人としても、チームとしても何かしらのサンプルゲームを作ってみたいという話になっているので、こうご期待。

これまでは WebGL 3D といえば three.js 一強の時代でしたが、これからは babylon.js も同じか、それ以上の強みを持って競争に加わってくるはずです。 babylon.js はいいぞ。

また、2019年5月31, 6月1日に開催されるOSC Hokkaido 2019 において、 6/1 11:00 から 楽しいVR空間を作る技術と支える技術というお題目で講演を行わせていただきます。
この babylon.js 含めザ・シードオンラインで利用されている Laravel, nuxt.js などの OSS 技術スタックをまとめて紹介しようと思いますので、是非お越しください!