原神のホームページで、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に保存する機能を付けました。また、マウスの右クリック・左クリックと一緒にマウスを動かすことで、カメラの位置を変えたり、マウスのスクロールで近づいたり遠ざかったりできます。
タイル表示では、2つのダンスを並べて表示できます。
原神のたくさんあるモデルから好きなものを選べます。
また、VMDのアニメーションのほかに、VPDによるポーズも選択できるようにしました。
ここで、「open」ボタンを押下すると、今見ているモデルが別タブで全画面表示で開きます。
こっちが、全画面表示。
#構築方法
①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を切り替えることもできます。
④原神のダウンロード
その前に、ダウンロードファイルはRARで暗号化されているため、以下の解凍アプリをダウンロード、インストールしておきます。
「7-Zip」
https://sevenzip.osdn.jp/
※解凍アプリによっては、RARファイルの解凍に失敗してしまうようです。
以下のページを開きます。
原神のキャンペーン公式サイト(中国語)
http://ys.biligame.com/gczj/
いくつかの模型が選べます。
試しに「琴」を選択します。そうすると、「qin.rar」といるファイルがダウンロードできます。
展開したファイルを、Webサーバにコピーします。
コピー元ファイル
琴/*
コピー先
public/mmd/qin/*
フォルダ名が中国語だったので、英語に変えています。
以下の通りに対応させていることを前提としています。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ですが、日本語名で「ジン」です。
ですので、キャラクタのセレクトボックスから「ジン」を選択します。
どうでしょうか、以下のように表示されましたでしょうか。
#ソースコード解説
基本的には、three.jsに付属のMMDLoaderを使っています。
で、扱いやすくするために、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に以下を記載しています。
<script src="dist/js/ammo.wasm.js"></script>
あとは、three.jsのサンプルが豊富ですし、リファレンスマニュアルもしっかりしているので、重宝しました。
https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene
##MmdView.jsの使い方
まずインポートします。
import { MmdView } from './MmdView.js';
※JS版では、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>
以下のようにインスタンス化します。
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を使う
他人には教えたくないWebでMMD
こちらもどうぞ。続編です。
「原神」のMMDをスマホでVR・ARする
「原神」のMMDキャラクタをスマホVRの世界に呼び込む
MMDダンスをM5Core2のディスプレイに表示する
#補足
長々と説明してきましたが、three.jsは、CDNで公開されているので、面倒であれば、以下をHTMLに追加するだけでよいです。
以下は、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版だったらこんな感じかな。
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';
以上