他人には教えたくないWebでMMD

久しぶり3Dモデルをブラウザ上で動かしたいと思い、調査し直してみました

Qiitaや個人ブログなど様々なサイトを参考にしたのですが現バージョンの方法が解説されていません

そのため、2019/07/03におけるモダンなブラウザ上で3Dモデルを動かす方法を記載しておきます

Three.jsとは

Web上でMMDを動かすにためにThree.jsを使用します

Three.jsとは、ウェブブラウザ上で簡単にコンピューターグラフィックス(CG)ができるJavaScirptライブラリです

簡単にコンピュータグラフィックスができるというところがポイントで、WebGLというWebに標準搭載されている技術があるのですが、これで作るのは大変むずかしいため、Three.jsで簡単にCGができるようになっています

公式サイト:

概要(wiki):

また、MMDを使用するにはメインライブラリであるThree.jsの他に、モジュール的なものであるmmdparser.min.jsやMMDLoader.js等が必要です

さらに、Three.jsは最近?Documentが更新されて大変見やすくなりました

以前はソースコードがドーンとあるだけで「見ればわかるやろ」状態で大変わかりづらかった記憶があります

MMDを動かすのに参考になる箇所をピックアップしておきます

Three.jsは更新スピードがはやい

今日(2019/07/03現在)、Three.jsのバージョンはr106となっています

r105からr106への更新間隔めっちゃ早かったです

更新内容は以下のサイトで確認することができます

JavaScript 3D library. Contribute to mrdoob/three.js development by creating an account on GitHub.

MMDを使用する上で必要なライブラリもちょいちょい更新がかかっているので作る上では見たほうが良いと思います

ブラウザ上でMMDを動かしてみる

「Three.js MMD」で調べると、実際にMMDで動かすプログラムはでてきますが、前のバージョンだったり、モデルやVMDのロード方法がコールバック地獄で書かれていたりして大変見づらいです

そのため、現在(2019/07/03現在)の最新バージョンであるr106でMMDを動かしてみつつ、async awaitを使うことでプログラムを見やすくしてみました

はじめに動いているところ

プログラムを掲載する前に期待通りに動いている動画を貼り付けておきます

プロ生ちゃんを動かしています

プログラム

重要な箇所であるmain.jsを掲載しておきます

すべてを見たい人はgithubをプログラムを上げていますのでご確認ください

Three.js ver_r106にてMMDを喋らせるサンプルプログラム. Contribute to Momijinn/SampleWebMMD development by creating an account on GitHub.

プログラム解説

動かす方法はGithubにあげているので割愛するとして、ここではプログラムの解説をします

全体的な流れ

プログラムの全体的な流れは、

  1. カメラ(視点)や光の定義
  2. PMXファイルを読み込む
  3. 複数のVMDファイルを読み込む
  4. 複数のAudioファイルを読み込む
  5. 再生

となっています

動かしたいMMDモデルとモーション

はじめにグローバル変数で読み込みたいPMXMotionObjectsを定義してあげます

MotionObjectsという連想配列の中に読み込むVMDやAudioをID管理で格納しています

読み込んだVMDやAudioはこの配列に格納されます

MotionObjectsで少しトリッキーに作っているのがAudioClipです

idがloopだけfalseになっていますが、これには理由があります

vmdによっては音を出すもの(しゃべるや歌う等)の他にも、発話せずに動いているだけということをしたいときがあると思います

後々にAuidoを読み込むための箇所(new THREE.AudioLoader().load)がありますが、このAudioを読み込むかどうかのFlagをAudioClipをここに入れています

trueであれば、audioに格納されているmp3を読み込み、読み込まれたAudioのオブジェクトはAudioClipに格納されます

falseの場合はfalseのままです

window.onload

HTMLが読み込みが完了後(window.onload)、Init()とLoadModeler()とRender()が呼ばれます

Init()

Init()は、カメラや証明、描画する範囲の指定をしています

LoadModeler()

LoadModeler()は、PMXとVMDとAudioを読み込んでいます

この関数がこのプログラムで重要な箇所になります

ほとんどのサイトではここをコールバッグ地獄で記述しています

また、Three.jsのVer.r93以前を使っているケースがほとんどです

r93以前は、THREE.MMDLoaderでPMXとVMDを読み込みができましたが、r93以上はTHREE.MMDAnimationHelperというものが加わり、少しVMDの読み込み方が変わりました

これらを踏まえて、モダンな書き方はどうするのかと調査ししつつ今どきは(たぶん)こんな書くのかということで、コールバッグ地獄にならないようにasync awaitで書くとことでわかりやすしました

また、VMDの読み込み方もthree.jsの現バージョン(2019/07/03現在)らしく書いてみました

読み込んだあとはVmdControl()というVMDの切り替えを行う関数へ渡しています

VmdControl(id, flag)では、再生してほしいIDとループするかしないかのFlagを投げてあげます

IDはMotionObjects内に定義しているものを渡して上げてください

MotionObjects内に存在しないIDが渡されると動きません(returnで返されます)

ループフラッグは、trueにするとループし、falseにすると一度だけ再生されます

この関数で重要なのは、mixerという変数です

r93以上からTHREE.MMDAnimationHelperにmesh(PMXを読み込んだオブジェクトファイル)とVMDを読み込んだオブジェクトファイルを合体させて再生をします

そして、デフォルトでは永久ループする設定になっているため、ループさせないアニメーションの場合は別途一度だけの再生をするように設定しないといけません

このループをさせるかさせないかは、どうあがいてもわからなかったのでTwitterで開発者本人聞いて解決をしました

takahiro(John Smith)@superhoge 様、本当にありがとうございます

質問内容(一部抜粋)

ループ終了イベントと一度だけのモーション再生の終了イベントはmixerのaddEventListenerにて”loop”と”finished”で受け取れます

Render()

Render()ではアニメーションの描画をしています

helper.update(clock.getDelta());で1コマずつ再生しています

注意点

Web上でMMDを動かす方法は一通り説明しましたが、今回作成したプログラムは物理演算を付与していません

物理演算を付与できることはできるのですが、モーションを変え続けると以下のエラーがでます

Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value 67108864, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which adjusts the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0

物理演算を計算しているammo.jsにてメモリがたりねーわと言われているような気がします

物理エンジンを切れば、私が試したところでは上記のエラーは発生しません

解決策をお待ちしています

ちなみに物理エンジンはhelper.addのところで付与することができます

その他

プログラムについていろいろ説明してきましたが、やはりMMDをいじるときはMMDの動画を見ながらかつ、聞きながらやる必要があると思います

Youutbeやニコニコ動画でMMDの動画をみながらやると捗ります

ぜひやってみてください

おすすめ

大変かわいい

参考

ライセンス関係

このプログラムはプロ生ちゃん(暮井 慧)を利用して作成しました

スポンサーリンク




コメント

  1. ぬこさん より:

    こんにちは。
    この記事の、Github上にあるソースコードを使わせていただいたのですが、エラーが出てしまいます。
    エラーは、chromeのコンソールにて、
    Uncaught TypeError: MotionObjects[index].AudioClip.play is not a function
    at VmdControl (main.js:149)
    at PoseClickEvent (main.js:214)
    at HTMLInputElement.onclick ((index):20)
    と出てきます。
    AudioClip: trueにした場合のみ出てきます。
    ※audioフォルダにidの名前のmp3ファイルはしっかりと入れています。

    • miyakawa より:

      エラーメッセージを見ますと正しくモデルデータが読み込まれていないと推測します。
      そのため、正しくモデルデータが入っているか確認させてください。

      モデルのデータは、 “/SampleWebMMD/pmx/pronama” に格納します。
      pronama ディレクトリに、プロ生ちゃんの モデルデータやテクスチャデータを入れていますでしょうか。
      eg) プロ生ちゃん.pmx, hadashi.png, pronama_skirt.png

      今一度確認お願いします。