Edited at

UnityでVRMファイルをインポートして使うときの覚え書き

More than 1 year has passed since last update.


はじめに

2018年4月に、ドワンゴが「VRM」という新しい3Dアバターフォーマットを公開しました。

今回はこのVRMをUnity上で利用する方法についてのメモ書きです。

(随時追加します。)

なお、この記事は「VRMファイルをUnity上でどう扱うか」についての記事です。

3DモデルをVRMファイルに変換する話はしません。


一緒にみると良いかもしれない資料

以前作った、VRのアバターをARで操作するシステム(twitter)について解説した資料です。

この資料でも触れているVRMについての情報をこの記事は含んでいます。


使い方メモ


0.UniVRMの各種使い方など

まずは公式ドキュメントを読みましょう。

下の方にBlendShape(表情変更)のやり方についての説明とかあります。


1. UniVRMの導入

UnityでVRMを利用する場合はUniVRMを用いることになるでしょう。

公式でサポートされているVRMインポータ/エクスポータです。

導入方法は簡単で、releaseページから最新のunitypackageをダウンロードして導入すればOKです。

なお、2018年6月時点ではUniVRMは週に1~2回の頻度でアップデートが実行されています。

アップデートのたびに微妙に仕様が変更されたり、バグって壊れたりすることがあるので小まめにバージョンを確認することを推奨します。


2. VRMモデルのインポート方法

VRMファイルをUnityで利用する方法は2パターンあります。


  • Prefab化する

  • ランタイムロードする


Prefab化する方法

VRMファイルをUnityの/Assets以下に配置した場合、自動的にUniVRMがインポートしてPrefabに変換してくれます。

ビルドにVRMモデルを埋め込んでしまう場合はこのPrefabを直接使う方法が楽です。

image.png


ランタイムロードする方法

VRMをスクリプトからランタイムロードすることで、動的にVRMモデルをGameObjectとしてシーン上に出現させることができます。

ランタイムロードする場合は、VRMファイルをStreamingAssetsなどに配置するとよいでしょう。


一番単純なロード方法

void Start()

{
var path = Application.streamingAssetsPath + "/" + "AliciaSolid.vrm";

// Actionコールバックで生成されたGameObjectが返される
VRMImporter.LoadVrmAsync(path, gameObject =>
{
gameObject.transform.position = new Vector3(1, 1, 1);
});
}


なお、UniVRMがv0.37以降であればasync/awaitを用いてロード待ちをすることができます。


async/await

async void Start()

{
var path = Application.streamingAssetsPath + "/" + "AliciaSolid.vrm";

// awaitでロード待機
var gameObject = await VRMImporter.LoadVrmAsync(path);

gameObject.transform.position = new Vector3(1, 1, 1);
}



おすすめのロード方法

WWWを使って先にbyte[]ファイルを読み込んでしまい、それをVRMImporter.LoadVrmAsyncに渡す方法を推奨します。

理由は次の2点です。



  • VRMImporter.LoadVrmAsyncが内部でFile.ReadAllBytesを使用しており、これが同期読み込みのため重い(v0.38時点)


  • StreamingAssets以下のファイルはAndroid実機の場合はWWW経由じゃないとアクセスできない


WWWを使ったロード方法

IEnumerator LoadVrmCoroutine(string path, Action<GameObject> onLoaded)

{
var www = new WWW(path);
yield return www;
VRMImporter.LoadVrmAsync(www.bytes, onLoaded);
}

void Start()
{
var path = Application.streamingAssetsPath + "/" + "AliciaSolid.vrm";

StartCoroutine(LoadVrmCoroutine(path, go =>
{
go.transform.position = new Vector3(1, 1, 1);
}));
}


ちなみに、UniRxを導入してasync/awaitと組み合わせるとこう書けます。最高では?


UniRx+async/await+WWW

async void Start()

{
var path = Application.streamingAssetsPath + "/" + "AliciaSolid.vrm";

var www = new WWW(path);

await www;

var go = await VRMImporter.LoadVrmAsync(www.bytes);

go.transform.position = new Vector3(1, 1, 1);
}



3.指の曲げ伸ばし

いろいろ手法があると思うけど、自分はこのスクリプトをAddComponentして使っています。


使い方

// 対象アバターのGameObjectのrootにアタッチ

var fingerController = gameObject.AddComponent<FingerController>();

// 左手全部曲げる
fingerController.FingerRotation(FingerController.FingerType.LeftAll, 1.0f);

// 右手の人差し指だけ伸ばしてあと全部曲げる
fingerController.FingerRotation(FingerController.FingerType.RightAll, 1.0f);
fingerController.FingerRotation(FingerController.FingerType.RightIndex, 0.0f);


1.gif

両手全部曲げ伸ばししてる画像(Lerp入れるとなめらかになってよさそう)


とりあえずここまで

発見があれば追記します