😁

Three.jsでVRM1.0を表示、操作する

2023/08/27に公開

はじめに

この記事で対象とするのは以下のような方です。

  • Three.jsでオブジェクトを表示することはできる
  • ヒューマノイドを表示してみたい
  • VRM1.0になってからよくわからない

以下の記事を参考に、手足の操作を加えたものになります。重複部分はお許しください。
https://zenn.dev/naruya/articles/e4642d817f77bf
https://qiita.com/hibit/items/0d119d171bcbe3b2c1c5
https://note.com/npaka/n/n477c15fedaef

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モデルです。かわいい!
https://3d.nicovideo.jp/works/td32797

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