Three.jsでVRM1.0を表示、操作する
はじめに
この記事で対象とするのは以下のような方です。
- Three.jsでオブジェクトを表示することはできる
- ヒューマノイドを表示してみたい
- VRM1.0になってからよくわからない
以下の記事を参考に、手足の操作を加えたものになります。重複部分はお許しください。
VRMについて
VRMドキュメントによると
「VRM」はVRアプリケーション向けの人型3Dアバター(3Dモデル)データを扱うためのファイルフォーマットです。 glTF2.0をベースとしており、誰でも自由に利用することができます。
とのことです。日本の岩城進之介(@MobileHackerz)氏が設計したことに始まるものらしく、公式ドキュメントも日本語が充実しています。
従来のVRM0.x(2018-2022)と最新のVRM1.0(2022-)では仕様がかなり変更になっていますが、まだ情報が少ない印象です。
モジュールを用意
必要なのは以下です。
- Three.js
- @pixiv/three-vrm
@pixiv/three-vrmにかんしては、適当なディレクトリにjsファイルを作成し、こちらからthree-vrm.jsをまるっとコピペしました。npmとか使ったらいいんでしょうけど、あまり理解できてなくて...力技です。
VRMファイルを用意
こちらから入手します。このアリシア・ソリッド(本名:ニコニ立体ちゃん)はドワンゴが配布している、表記不要で無料で使える3Dモデルです。かわいい!
GLTFLoader
VRMはGLTF2.0をもとにしたファイル形式なので、GLTFLoaderで読み込みます。GLTFのときと同じ記法でゴリ押すと...表示はできます。ただ、それでは固定したモデルと変わりません。VRMとして、つまり手足や表情を操作するには「VRMインスタンス」である必要があります。次のように記述しましょう。
<script type="module">
import * as THREE from "three";
import { GLTFLoader } from "GLTFLoader";
import { VRMLoaderPlugin } from '@pixiv/three-vrm';
//中略
const loader = new GLTFLoader();
loader.register((parser) => {
return new VRMLoaderPlugin(parser);
});
loader.load("vrmファイルのパス", (gltf) => {
// ここでVRMインスタンスを取得
const vrm = gltf.userData.vrm;
//sceneに加えます
scene.add(vrm.scene);
// デバッグしやすくなります。入れておくことをオススメします
console.log(vrm);
},);
//中略
</script>
手と表情を操作する
個人的に一番困ったところです。公式ドキュメントのexampleを発見して解決しました(three-vrm example)。やはり公式をよく読むのが最も手堅いですね。次のように記述します。
vrm.expressionManager.setValue('happy', 0.7);
//vrm.expressionManager.setValue( 'aa', 1.0);
vrm.humanoid.getNormalizedBoneNode( 'leftUpperArm' ).rotation.z = 1.1;
vrm.humanoid.getNormalizedBoneNode( 'rightUpperArm' ).rotation.z = -1.1;
vrm.expressionManager.update();
vrm.humanoid.update();
これで表情、手足が操作できます。
アニメーションさせたい場合は先ほどのexampleのリンクから、開発者ツールを開いてよく見てみましょう。(アニメーションについては別記事にまとめようか検討中です。)
全体のコードです
<script type="module">
import * as THREE from "three";
import { GLTFLoader } from "GLTFLoader";
import { VRMLoaderPlugin } from '@pixiv/three-vrm';
//中略
const loader = new GLTFLoader();
loader.register((parser) => {
return new VRMLoaderPlugin(parser);
});
loader.load("../../assets/vrm/AliciaSolid.vrm", (gltf) => {
// ここでVRMインスタンスを取得
const vrm = gltf.userData.vrm;
// add the loaded vrm to the scene
scene.add(vrm.scene);
// デバッグしやすくなります。入れとくことをオススメします
console.log(vrm);
vrm.expressionManager.setValue('happy', 0.7);
//vrm.expressionManager.setValue( 'aa', 1.0);
vrm.humanoid.getNormalizedBoneNode( 'leftUpperArm' ).rotation.z = 1.1;
vrm.humanoid.getNormalizedBoneNode( 'rightUpperArm' ).rotation.z = -1.1;
vrm.expressionManager.update();
vrm.humanoid.update();
},
// called while loading is progressing
(progress) => console.log('Loading model...', 100.0 * (progress.loaded / progress.total), '%'),
// called when loading has errors
(error) => console.error(error),
);
Discussion