MMDLoaderでローカル(IndexedDB)に保存したモデルを表示するテストを作ってみた

はじめに

Three.jsにはMMDLoaderという、MMDモデル(pmd, pmxファイル)を読み込んで表示してくれるライブラリがあります。

これ使ってMMDモデルを表示するARアプリなんかを作っている方もいるらしいです。→ https://qiita.com/jyuko/items/727a4f90e914a3932be2

しかし、MMDモデルの著作権の関係でデモページを公開できないようです。

そこで、MMDモデルはページにアクセスする人自身が用意してアプリに直接アタッチできるようにできないか、ということを試してみようと思いました。

簡単なのは一旦サーバーにアップロードする方法ですが、これはサーバーにモデルファイルが残ってしまい著作権的にグレーな気がします。 また、使うのはあくまでユーザ一人なので、使うときにいちいちサーバーから引っ張ってくる、というのは効率が悪いと思います。

そこで今回は、ブラウザからアクセスできるローカルのストレージであるIndexedDBにモデルを保存する仕組みを作ってみました。

何をしているか

MMDSaver.js

  1. フォームをリスンしておき、イベントがあればIndexedDBのトランザクションを開く
  2. ArrayBufferに変換して保存
  3. 保存が終わったら取り出す
  4. 取り出したモデルを修正版MMDLoaderに渡し、返ってきたmeshをsceneに追加
  5. レンダリング

MMDLoader

修正前

MMDLoaderのロード系メソッドは第一引数に静的ファイルのパスを渡す仕様になっています。MMDLoader内ではこのパスに基づいて xhrリクエストをサーバーに送信し、レスポンスとしてArrayBuffer形式のモデルファイルを受け取っています。 このことから、第一引数に直接ArrayBufferを渡し、xhrリクエストを送る処理を飛ばすようにすればいけると思いました。

修正後

MMDLoaderのロード系メソッドは第一引数に静的ファイルのパスを渡す仕様になっています。なのでそのままblobなどを渡してみてもエラーになります。 そこで

  1. 第一引数がblobのインスタンスの場合は分岐
  2. blobをpmd/pmxParserで処理可能なArrayBufferに変換
  3. pmd/pmxParserでArrayBufferをビルドできる形式に変換

するように修正しています。

データの変換

いろいろいじっています。複雑なので図にしてみました。

f:id:gakki-uec15:20190930163327p:plain
モデルデータの変換手順
この中で

  1. まず、IndexedDBはオブジェクト形式でしか保存できないため、バイナリ(と思われる)pmd/pmxファイルをArrayBufferに変換
  2. MMDLoaderに渡すとき、ArrayBufferのままだとなぜか失敗したので、一度blobに変換

という理由で処理が入っています。

結果

デモページを用意しました。

フォームからpmd/pmxファイルを選択すると、そのモデルに切り替わります。(pmd/pmxファイルを持っていない方は「MMDモデル 配布」とかでググってください)

また、そのモデルはIndexedDBに残っているのでページをリロードしても最後に登録したモデルファイルがそのまま表示されます。

もちろんサーバーにモデルファイルが送信されることはないので著作権的にも大丈夫(なはず)です。

Github

https://github.com/one-color-low/MMDSaver

今後やりたいこと

  • テクスチャを張れるように
    • さすがにテクスチャなしはさみしい
    • pmdファイルの内部にテクスチャがパスとして入ってるっぽくて、IndexedDB内にどう保存するかがムズい
  • クロスドメイン対応
    • このモデルアップロードページを起点として、ほかのアプリでも簡単にローカルのモデルファイルを呼び出せるようにしたい。
    • しかし、IndexedDBは同じドメインからしかアクセスできない。
    • そこで、このページをサーバー化し、別のアプリに送信できるようにする。
    • https://news.mynavi.jp/article/20100909-localstrage-on-many-domains/ ← こんな感じ

まとめ

「MMDLoaderを使ったWebアプリを作ってみたけど公開できない!」という方の助けになれば幸いです。 また、最終的にはMMDモデルを使ってWebで動くオープンワールドのゲームみたいのを作ってみたいと思っています。