じゅころぐAR

ARのブログ

three.jsでWebVRを行うための基本的なところ

久々の投稿デス。

WebXRやろうかなと思ったのですが、手持ちのARCore対応デバイスがAndroid7.xのため試せず・・・で気分転換にWebVRをやりました。

はじめに

three.jsに関する基礎知識を持っている前提で書いているので、three.jsをさわったことがない!という方は、他の記事やサイトも合わせて読んでください。

開発環境については、以下となっております。(WiFiルータ経由でローカル通信)

  • Webサーバ
  • クライアント
    • ASUS Zenfone AR
    • Chrome 69
    • Daydream View & Daydream Controller

three.jsでVRMを扱う

VRMLoader.jsを使って、VRMを表示させることができます。
公式のexampleは以下。

VRMはglTF2.0ベースなので、GLTFLoader.jsでも読み込みは可能です。
上記のVRMLoader.jsも内部でGLTFLoader.jsをラップしています。

UniVRMでエクスポートする

まず、VRMモデルを用意します。
今回は公式の手順に従い、FBXファイルをUniVRMでエクスポートしてみました。

VRMファイルを作ってみたい - dwango on GitHub

モデルはいつもの(クエリちゃんSDモデル)です。

assetstore.unity.com

手順の通り、Humanoidリグが設定されているモデルをエクスポートするだけなので簡単。

f:id:jyuko49:20181008222525p:plain

こんな感じで、three.jsで使えるようになります。

f:id:jyuko49:20181008223306p:plain

ボーンアニメーションで動かす

FBXからエクスポートしたVRMにはアニメーションが付いていないので、何もしないとTポーズのままになります。
それだと面白くないので、ボーンを使って動きを付けます。

ボーンを確認する方法として、LoadしたVRMモデルの情報をconsoleに表示させました。

var loader = new THREE.VRMLoader();
loader.load( 'SD_QUERY_01.vrm', function (vrm) {
  console.log(vrm);
  ...
}

MacのWebブラウザでページを開いてconsoleを見ると、VRMの構造が確認できます。

f:id:jyuko49:20181008230138p:plain

scene内にモデルが含まれるので、sceneのchildrenを辿っていくと、SkinnedMeshが見つかるはずです。SkinnedMeshはskeletonプロパティにbonesを持っていて、このbonesを回転させれば、モデルが動きます。

ボーンアニメーションについては、カヤックさんのブログがわかりやすかったです。

techblog.kayac.com

とりあえず、動かしてみました。

中央にいるSDクエリちゃんの回転と首振りがボーンアニメーションです。

一方、隣でキレキレのダンスを披露しているコロちゃん(コロコロ*1 )は、元のモデルがMMDでMMDLoader.jsでVMDファイルをAnimationClipとしてLoadしています。
複雑なモーションの場合、ボーンをスクリプトで直接動かすのはつらいので、何らかの手段でAnimationClipを作った方がいいです。

three.jsのシーンをWebVRに対応させる

exampleを参考にthree.jsのシーンをVRで表示させます。

通常のスクリプトから以下の点を変更すればOKのよう。

// WebVR.jsを読み込む
<script src="examples/js/vr/WebVR.js"></script>

<script>
  renderer = new THREE.WebGLRenderer( { antialias: true } );

  // rendererでVRを有効にする
  renderer.vr.enabled = true;

  // createButtonで"Enter VR"ボタンを表示する
  document.body.appendChild(WEBVR.createButton(renderer));

  function animate() {
    // setAnimationFrameではなく、setAnimationLoopでループさせる
    renderer.setAnimationLoop(animate);
    render();
  };
</script>

Daydreamで表示させるとこんな感じになります。

Daydreamコントローラーを使う

Gamepad Extensionsを有効化する

three.jsのexamplesでは、renderer.vr.getController()でDaydreamコントローラーの情報が取れているのですが、ローカルで実行すると動きませんでした。

GoogleのDevelopers Guideによると、ChromeブラウザでGamepad API 拡張機能を有効にしないと動かないようです。 Adding Input to a WebVR Scene  |  Web Fundamentals  |  Google Developers

Chromeブラウザのアドレスバーにchrome://flagsと入力して、設定画面を開き、"Gamepad Extensions"、"WebXR Gamepad Support"をEnabled(有効)にすると動くようになります。

f:id:jyuko49:20181009083731j:plain

Ray Inputで代用する

開発者向けであれば、上記の設定を行えばいい話ですけど、一般のユーザに自身のデバイスでデモを体験させたいときなど、設定を変えてもらうのはちょっと手間です。

代案として、先程のGoogleの記事に記載されていたRay Inputであれば、拡張機能の設定なしに動きます。

github.com

Daydream(モバイルVR)の場合、オブジェクト選択に使うRayがコントローラーの向きに関わらず、視点の中心になりました。
click等はDaydreamコントローラーの操作がイベントとして取れます。

空間内の移動を実装する

three.jsで移動を実装する場合、cameraオブジェクトのposition、rotationを操作すれば視点が変わり、プレイヤーが移動しているように見えます。
ただ、WebVRの場合はcameraがVRデバイスと連動するため、cameraのプロパティを直接操作しても視点が変わりません。

// three.jsでは移動するけど、WebVRだと動かない・・・
camera.position.z -= 0.1;

これの解決策として、cameraの親オブジェクトを作ってあげて、camera直接ではなく親オブジェクトの方を動かすと位置が変わります。

// Object3Dでplayerを作り、cameraを親子関係にする
var player;
player = new THREE.Object3D();
scene.add(player);
player.add(camera);

// playerを動かすとcameraも動いて視点が変わる
player.position.z -= 0.1;

playerの移動をコントローラー入力のイベントに連動させれば、3DoFデバイスでも空間上の前進、後退くらいは実現できます。

まとめ

今回の内容でthree.jsのシーンをWebVR対応させ、キャラクター(VRM)を表示させて、コントローラーで入力や移動を行うところまで実装できました。
若干の差異はあれど、通常のthree.jsとほぼ変わらないので、元々three.jsをやっていた人なら簡単にVR開発ができます。

three.jsの場合、シーン構成からアニメーションまですべてスクリプトで完結する点とライブラリ・サンプルが豊富という点で、UnityやUEにはない安心感がありますね。(圧倒的ホームグラウンド感!)

Webなので、ネットワークを介したコンテンツの共有が楽ですし、VR内でのWebブラウジングからスムーズにVRコンテンツに移行できるので、安価なVRデバイスが普及していけば用途も広がりそうな感じはします。

*1:gdgd妖精sのBD特典モデル(Copyright (c) 2013 gdgd妖精s(ぐだぐだフェアリーーーズ), 2代目gdgd妖精s)、改造可・再配布・商用利用不可