「原神」がMMDモデルを配信してくれたので、JavascriptでMMDビューアを作った

原神のホームページで、MMDファイルを公開してくれました。太っ腹！

原神のキャンペーン公式サイトの紹介記事
　https://www.gamespark.jp/article/2020/10/08/102819.html

なので、これを機会に、JavascriptでMMDファイルを表示するビューアページを作ってみようと思います。

原神のキャンペーン公式サイト(中国語)
　http://ys.biligame.com/gczj/

ここから、MMDファイルをダウンロードします。
※現在は以下からダウンロードできます。
　https://genshin.mihoyo.com/ja/news/detail/5885

MMDファイルの表示には、three.jsにあるMMDLoaderを使いました。

mrdoob/three.js
　https://github.com/mrdoob/three.js

ということで、もろもろ作成したMMDビューアのソースコードは以下に置いておきました。

poruruba/MmdViewewr
　https://github.com/poruruba/MmdViewer

各種データファイルは著作権の関係上置けなかったので、上記から各人でデータを取り寄せて構築してください。
VMDファイルやVPDファイルは、とりあえず、three.jsに付属のものを使います。

（ちなみに）
MMDとは、MikuMikuDanceの略
　https://ja.wikipedia.org/wiki/MikuMikuDance
PMXファイルまたはPMDファイルが3Dモデルのファイルです。
VMDファイルがモーション(動き)のファイル、VPDファイルがポーズ(静止)のファイルです。

#MMDビューア画面

Bootstrap上にタイル表示させたページと、全画面表示のページの2種類を用意しました。
各ページでは、ダンスを一時停止したり、スナップショットをJpegに保存する機能を付けました。また、マウスの右クリック・左クリックと一緒にマウスを動かすことで、カメラの位置を変えたり、マウスのスクロールで近づいたり遠ざかったりできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/d29cb6c1-9604-94f7-a130-fa34b12aa681.png)

タイル表示では、2つのダンスを並べて表示できます。
原神のたくさんあるモデルから好きなものを選べます。
また、VMDのアニメーションのほかに、VPDによるポーズも選択できるようにしました。
ここで、「open」ボタンを押下すると、今見ているモデルが別タブで全画面表示で開きます。

こっちが、全画面表示。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/43236259-fad3-ac55-379f-f5769d645eff.png)


#構築方法

①Webサーバの立ち上げ

Webサーバに今回のMMDビューアページを配置します。
以下から、ZIPをダウンロードしてきます。

poruruba/MmdViewer
　https://github.com/poruruba/MmdViewer

すでに別にWebサーバを立ち上げてあるのであれば、そこにコンテンツを配置すればよく、以下の作業は不要です。
肝心のコンテンツは、publicフォルダにあります。

```
> unzip MmdViewer_master.zip
> cd MmdViewer_master
> npm install
> node app.js
```

これで、Webサーバが立ち上がります。特に変更しなければ、ポート10080で開くかと思います。

②three.jsの配備

以下から、ZIPをダウンロードします。結構でかいです。

mrdoob/three.js
　https://github.com/mrdoob/three.js

※今後three.jsがバージョンアップすると動かなくなるかもしれません。本日時点では、r121 でした。

ZIP展開し以下のファイルを立ち上げたWebサーバにコピーします。

コピー元
　three.js-dev/examples/models/mmdフォルダ
コピー先
　public/mmd

コピー元
　three.js-dev/build フォルダ
コピー先
　public/mmd_viewer_jsm/dist/build

コピー元
　three.js-dev/examples/jsmフォルダ
コピー先
　public/mmd_viewer_jsm/dist/js/jsm

コピー元
　three.js-dev/examples/js/libs/{ammo.wasm.js, ammo.wasm.wasm}
コピー先
　public/mmd_viewer_jsm/dist/js/{ammo.wasm.js, ammo.wasm.wasm}

これで準備ができました。

※JS版three.jsのセットアップ

先ほどのセットアップは、moduleタイプの場合でした。
他のライブラリと連携する際に、moduleタイプではなく、通常のJavascriptとして利用したい場合は、以下の通りにします。
ただし、すでに、moduleタイプではない通常のJavascript版は、three.js r116でdeprecatedとなっているそうで、r124では使えなくなるそうです。。。

コピー元
　three.js-dev/examples/models/mmdフォルダ
コピー先
　public/mmd
※これは同じ

コピー元
　three.js-dev/build フォルダ
コピー先
　public/mmd_viewer_js/dist/js/three

コピー元
　three.js-dev/examples/jsフォルダ
コピー先
　public/mmd_viewer_js/dist/js/three/examples

mmd-parserがないようで、以下からダウンロードし、解凍後、以下のようにコピーします。

takahirox/mmd-parser
　https://github.com/takahirox/mmd-parser

コピー元
　mmd-parser/buildフォルダ
コピー先
　public/mmd_viewer_js/dist/js/mmd-parser

③初音ミクの表示

とりあえず、初音ミクだけはthree.jsに付属しているので、それを表示させてみましょう。
ブラウザから、以下を開きます。

　http://localhost:10080/index.html

※JS版は以下です。
　http://localhost:10080/mmd_viewer_js/index.html

そして、セレクトボックスから初音ミクを選択します。表示されたかと思います。
vmdやvpdを切り替えることもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/9c006e55-906a-defc-b201-6687a51cabd0.png)

④原神のダウンロード

その前に、ダウンロードファイルはRARで暗号化されているため、以下の解凍アプリをダウンロード、インストールしておきます。

「7-Zip」
　https://sevenzip.osdn.jp/

※解凍アプリによっては、RARファイルの解凍に失敗してしまうようです。

以下のページを開きます。

原神のキャンペーン公式サイト(中国語)
　http://ys.biligame.com/gczj/

いくつかの模型が選べます。
試しに「琴」を選択します。そうすると、「qin.rar」といるファイルがダウンロードできます。

展開したファイルを、Webサーバにコピーします。

コピー元ファイル
　琴/*
コピー先
　public/mmd/qin/*

フォルダ名が中国語だったので、英語に変えています。
以下の通りに対応させていることを前提としています。start.jsに記載しています。

```js:public/js/start.js
var pmx_list = [
    {
        fname: 'mmd/miku/miku_v2.pmd',
        title: '初音ミク'
    },
    {
        fname: 'mmd/ando/安柏.pmx',
        title: 'アンバー'
    },
    {
        fname: 'mmd/wendi/温迪.pmx',
        title: 'ウエンティ'
    },
    {
        fname: 'mmd/kaiya/凯亚.pmx',
        title: 'ガイア'
    },
    {
        fname: 'mmd/qin/琴.pmx',
        title: 'ジン'
    },
    {
        fname: 'mmd/diluke/迪卢克.pmx',
        title: 'ディルック'
    },
    {
        fname: 'mmd/babala/芭芭拉.pmx',
        title: 'バーバラ'
    },
    {
        fname: 'mmd/paimeng/派蒙.pmx',
        title: 'パイモン'
    },
    {
        fname: 'mmd/feixieer/菲谢尔.pmx',
        title: 'フィッシュル'
    },
    {
        fname: 'mmd/lisha/丽莎.pmx',
        title: 'リサ'
    },
    {
        fname: 'mmd/ningguang/凝光.pmx',
        title: '凝光'
    },
    {
        fname: 'mmd/kong/空.pmx',
        title: '空'
    },
    {
        fname: 'mmd/ying/女主角.pmx',
        title: '蛍'
    },
    {
        fname: 'mmd/xiangling/香菱.pmx',
        title: '香菱'
    },
];
```

これを、欲しいキャラクタの分だけ実施します。
配置が終わったら、またブラウザから、以下を開きます。

　http://localhost:10080/index.html

先ほどダウンロードしたのは、qinですが、日本語名で「ジン」です。
ですので、キャラクタのセレクトボックスから「ジン」を選択します。
どうでしょうか、以下のように表示されましたでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/7ec5f177-03bf-0ee4-4b6e-ec2cc435147e.png)

#ソースコード解説

基本的には、three.jsに付属のMMDLoaderを使っています。
で、扱いやすくするために、MmdView.jsというのを作っています。

内部で以下をインポートしています。

```js:public/js/MmdView.js
import * as THREE from '../dist/build/three.module.js';

import { OrbitControls } from '../dist/js/jsm/controls/OrbitControls.js';
import { OutlineEffect } from '../dist/js/jsm/effects/OutlineEffect.js';
import { MMDLoader } from '../dist/js/jsm/loaders/MMDLoader.js';
import { MMDAnimationHelper } from '../dist/js/jsm/animation/MMDAnimationHelper.js';
```

あと、ちょっとわかりにくいのですが、AMMO.jsも使っていますので、HTMLに以下を記載しています。

```html:public/index.html
  <script src="dist/js/ammo.wasm.js"></script>
```

あとは、three.jsのサンプルが豊富ですし、リファレンスマニュアルもしっかりしているので、重宝しました。
　https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene

##MmdView.jsの使い方

まずインポートします。

```js:public/js/start.js
import { MmdView } from './MmdView.js';
```
※JS版では、index.htmlに以下を加えます。

```html:index.html
  <script src="dist/js/three/three.js"></script>

  <script src="dist/js/mmd-parser/mmdparser.js"></script>
  <script src="dist/js/three/examples/libs/ammo.wasm.js"></script>

  <script src="dist/js/three/examples/loaders/MMDLoader.js"></script>
  <script src="dist/js/three/examples/animation/MMDAnimationHelper.js"></script>
  <script src="dist/js/three/examples/effects/OutlineEffect.js"></script>
  <script src="dist/js/three/examples/animation/CCDIKSolver.js"></script>
  <script src="dist/js/three/examples/animation/MMDPhysics.js"></script>
  <script src="dist/js/three/examples/controls/OrbitControls.js"></script>
```

以下のようにインスタンス化します。

```js:public/js/start.js
let mmd = new MmdView(canvas, width, height );
```

以下のようにして、PMXまたはPMDファイルを読みだします。
VMDファイルと一緒に読み出す場合は、
　await mmd.loadWithAnimation(pmxファイル名, vmdファイル名);
VPDファイルと一緒に読み出す場合は、
　await mmd. loadWithPose (pmxファイル名, vpdファイル名);
です。
あとは自動的に、動き出します。

mmd.resize(width, height)
　ブラウザの画面サイズが変わったときに、それに合わせて表示サイズを変えたい場合はこれを呼び出します。

mmd.start_animate()
mmd.pause_animate()
　自動的に動き出しますが、これで一時停止したり再開したりできます。

mmd.dispose()
　使い終わったら、解放します。

#おわりに

以下の投稿を参考にさせていただきました。ありがとうございました！
　[three.js でMMDを使う](https://qiita.com/shoichi1023/items/6cbaefe078c33f600bfe)
　[他人には教えたくないWebでMMD](https://www.autumn-color.com/archives/2048)

こちらもどうぞ。続編です。
　[「原神」のMMDをスマホでVR・ARする](https://qiita.com/poruruba/items/a1b41a10ca714c58e044)
　[「原神」のMMDキャラクタをスマホVRの世界に呼び込む](https://qiita.com/poruruba/items/89fd95f8bf00fc2154ad)
　[MMDダンスをM5Core2のディスプレイに表示する](https://qiita.com/poruruba/items/a2cd9606c630bea5f5bf)

#補足

長々と説明してきましたが、three.jsは、CDNで公開されているので、面倒であれば、以下をHTMLに追加するだけでよいです。
以下は、JS版です。

```js
  <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/build/three.js"></script>
  
  <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r106/examples/js/libs/mmdparser.min.js"></script>
  <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/js/libs/ammo.wasm.js"></script>
  
  <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/js/loaders/MMDLoader.js"></script>
  <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/js/animation/MMDAnimationHelper.js"></script>
  <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/js/animation/CCDIKSolver.js"></script>
  <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/js/animation/MMDPhysics.js"></script>
  <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/js/controls/OrbitControls.js"></script>
```

JSM版だったらこんな感じかな。

```js
import * as THREE from 'https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/build/three.module.js';

import { OrbitControls } from 'https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/jsm/controls/OrbitControls.js';
import { MMDLoader } from 'https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/jsm/loaders/MMDLoader.js';
import { MMDAnimationHelper } from 'https://cdn.jsdelivr.net/gh/mrdoob/three.js@r128/examples/jsm/animation/MMDAnimationHelper.js';
```

以上