3
0

More than 1 year has passed since last update.

VRMファイルをUnityで読み込む2つの方法

Posted at

はじめに

UnityでVRMファイルを読み込む2種類の方法をまとめました。
参考の記事を探してみても、半年前の記事がUniVRMのバージョンが上がり使えなくなっていたり、あまり参考にできなかったため、今の最新版のUniVRM(v0.98.0_2f6b)でも使えるように備忘録程度に残しておきます。
※本投稿では、著作権等に配慮しスクショ等は載せておりません。

(初投稿なので誤字脱字等あるかもしれませんがご容赦ください。)

目次

  1. 事前準備
  2. ローカル上のファイル読み込み
  3. サーバー上のファイル読み込み
  4. まとめ

1. 事前準備

この記事を見られる方はUnityは既にインストールしてあるものとしてUnityのインストールの手順は割愛させて頂きます。
今回利用したUnityのバージョンは2021.3.1f1です。4/13にUnity2021LTSがリリースされたため、早速使ってみました。

  1. UniVRMの導入

    1. UniVRMのリリースページから、4/30現在で最新のバージョンUniVRM_Samples-0.98.0_2f6b.unitypackageをダウンロードします。
    2. UnityEditorを開き、メニューバーのAssets/Import Package/Custom Package...を選択し、1.でダウンロードしたパッケージをインポートします。特に細かいこだわり等なければ何も考えずに全てインポートしてしまっていいと思います。※今回私も何も考えずに全てインポートしました。
  2. UniTaskの導入
    ※スキップ可。await/asyncを使いたいって方はこちらを参考にしてください。本投稿ではawait/asyncを使っていますが、Unityのコルーチンで行っても問題ありません。
    1. UniTaskのリリースページから、最新のバージョンUniTask.2.3.1.unitypackageをダウンロードします。
    2. UnityEditorを開き、メニューバーのAssets/Import Package/Custom Package...を選択し、1.でダウンロードしたパッケージをインポートします。

  3. VRMファイルの用意
    こちら、読み込みができているかどうかの動作確認用になります。

    1. 自作のものか購入したものをローカルのどこかに格納します。(Assets直下でも問題ありません)
    2. Microsoft AzureのBlob Storageでもその他AWSなど別のサービスでもいいため、.vrmのファイルをサーバー上にアップします。(https://○○.blob.core.windows.net/××/fileName.vrm の形式で読み込めるようになっていれば問題ありません。WebGLで読み込む場合、格納場所によってはCORSエラー等で読み込めない場合がありますのでご注意ください。)

2. ローカル上のファイル読み込み

コードがこちら↓

using Cysharp.Threading.Tasks;
using UniGLTF;
using UnityEngine;
using UnityEngine.Networking;
using VRM;
using VRMShaders;

namespace VRMTest
{
    public class VRMFileLoader : MonoBehaviour
    {
        /// <summary>
        /// ローカルのものを見に行くかどうか
        /// </summary>
        [SerializeField] private bool isLoal;

        /// <summary>
        /// 読み込みたいファイル名
        /// </summary>
        [SerializeField] private string fileName;

        private async void Start()
        {
            if (isLoal) await LoadLocalVrmFile(fileName);
        }

        /// <summary>
        /// ローカルファイルの読み込み
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private async UniTask LoadLocalVrmFile(string fileName)
        {
            // 指定したPathにある.vrmのファイルをGLTF形式にパースする
            // パースもDisposeしないとメモリリークしてしまうためusingを使用
            using var gltfData = new AutoGltfFileParser($"Assets/VRMAvatar/{fileName}.vrm").Parse();
            var vrm = new VRMData(gltfData);

            // Disposeしないとメモリリークしてしまうためusingを使用
            using var context = new VRMImporterContext(vrm);
            var instance = await context.LoadAsync(new RuntimeOnlyAwaitCaller());
            // シーン上にオブジェクト(メッシュ)表示
            instance.ShowMeshes();
        }
    }
}

注意点

  1. パースしているところ、VRMImporterContextのところ、この2カ所でDisposeをしていますが、それぞれDisposeしてやらないとメモリリークが起きてしまいます。
  2. instance.ShowMeshes()を呼んでやらないと、シーン上に読み込みはされるものの、表示がされないません。

3. サーバー上のファイル読み込み

コードがこちら↓
UnityWebRequest.Get()引数を事前準備でサーバーにあげたファイルのURLを渡してあげてください。

using Cysharp.Threading.Tasks;
using UniGLTF;
using UnityEngine;
using UnityEngine.Networking;
using VRM;
using VRMShaders;

namespace VRMTest
{
    public class VRMFileLoader : MonoBehaviour
    {
        /// <summary>
        /// 読み込みたいファイル名
        /// </summary>
        [SerializeField] private string fileName;

        private async void Start()
        {
            await LoadServerVrmFile(fileName);
        }

        /// <summary>
        /// サーバー上のファイルの読み込み
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private async UniTask LoadServerVrmFile(string fileName)
        {
            using var webRequest = UnityWebRequest.Get($"https://〇〇.blob.core.windows.net/××/{fileName}.vrm");
            await webRequest.SendWebRequest();

            // WebRequestで取得した.vrmのByteデータをGLTF形式にパースする
            // パースもDisposeしないとメモリリークしてしまうためusingを使用
            using var gltfData = new GlbBinaryParser(webRequest.downloadHandler.data, "").Parse();
            var vrm = new VRMData(gltfData);

            // Disposeしないとメモリリークしてしまうためusingを使用
            using var context = new VRMImporterContext(vrm);
            var instance = await context.LoadAsync(new RuntimeOnlyAwaitCaller());
            // シーン上にオブジェクト表示
            instance.ShowMeshes();
        }
    }
}

注意点

  1. パースしているところ、VRMImporterContextのところ、この2カ所でDisposeをしていますが、それぞれDisposeしてやらないとメモリリークが起きてしまいます。
  2. LoadAsyncnew RuntimeOnlyAwaitCallerを渡していますが、WebGLで使う場合、new ImmediateCallerを渡してやらないと読み込みが終わりません。※WebGLはマルチスレッド対応していないため
  3. instance.ShowMeshes()を呼んでやらないと、シーン上に読み込みはされるものの、表示がされないません。

まとめ

載せられる画像がなくすみません。。事前準備ができていれば、お手元でもご確認頂けるかと思いますので是非上記コードを試してみてください。改善できる部分等あればご指摘頂ければと思いますので、お気軽にコメントください。
余談ですがStartでもasyncが使えます。

ここまでご覧頂きありがとうございました。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0