アマゾンバナーリンク

ディスプレイ広告

スポンサーリンク

【Unity】VRMランタイムロード【UniVRM】

こんにちは!ジェイです。VRM形式のファイルを外部から読み込んで自分のゲームで動かせたら、楽しいと思いませんか?今回はその方法を解説します。

おおまかな内容はこちらの記事を参考にさせていただきましたが、新しいバージョンで仕様が変わっていた部分もあったので、詳細を解説します。

記事内広告

準備と環境

UnityとUniVRMは現時点の安定版で一番新しいバージョンを選んでいます。AnimationControllerはアニメーションをさせないなら必要ないです。最低限、上から3つは用意しましょう。

VRM読み込みまでの手順

Unityに以下画像を参考にUniVRMのパッケージをダウンロードしてインポートする。

読み込み用のスクリプト作成

UniVRMのドキュメントがこちらにあるので参考にします。

using UniGLTF;
using UnityEngine;
using VRM;
using System.IO;

namespace YourNameSpace
{
    public sealed class CVRMLoader : MonoBehaviour
    {
        [SerializeField]
        RuntimeAnimatorController _Animator;
        private GameObject VRMObject;

        private void Start()
        {
            // カレントディレクトリに置いてあるjay.vrmを読み込む
            VRMObject = LoadVrm(Directory.GetCurrentDirectory()+"\\"+"jay.vrm");
            SetComponent(VRMObject);
        }
        void SetComponent(GameObject go)
        {
            if (go != null)
            {
                Animator animator = go.GetComponent<Animator>();
                if (animator && animator.runtimeAnimatorController == null)
                {
                    // Animatorをセット
                    animator.runtimeAnimatorController = _Animator;
                    // 走るアニメーションを開始
                    animator.SetFloat("Speed", 1.0f);
                }
            }
        }

        private void OnDestroy()
        {
            DestroyVrm(VRMObject);
        }

        private GameObject LoadVrm(string file_name)
        {
            if (!File.Exists(file_name))
            {
                Debug.LogError("file not found path = " + file_name);
                return null;
            }
            // 1. GltfParser を呼び出します。
            //    GltfParser はファイルから JSON 情報とバイナリデータを読み出します。
            var parser = new GltfParser();
            parser.ParsePath(file_name);

            // 2. GltfParser のインスタンスを引数にして VRMImporterContext を作成します。
            //    VRMImporterContext は VRM のロードを実際に行うクラスです。
            using (var context = new VRMImporterContext(parser))
            {
                // 3. Load 関数を呼び出し、VRM の GameObject を生成します。
                context.Load();

                // 4. (任意) SkinnedMeshRenderer の UpdateWhenOffscreen を有効にできる便利関数です。
                //    https://docs.unity3d.com/2019.4/Documentation/ScriptReference/SkinnedMeshRenderer-updateWhenOffscreen.html
                context.EnableUpdateWhenOffscreen();

                // 5. VRM モデルを表示します。
                context.ShowMeshes();

                // 6. VRM の GameObject が実際に使用している UnityEngine.Object リソースの寿命を VRM の GameObject に紐付けます。
                //    つまり VRM の GameObject の破棄時に、実際に使用しているリソース (Texture, Material, Mesh, etc) をまとめて破棄することができます。
                context.DisposeOnGameObjectDestroyed();

                // 7. Root の GameObject を return します。
                //    Root の GameObject とは VRMMeta コンポーネントが付与されている GameObject のことです。
                return context.Root;
            }
            // 8. using スコープを抜けて context が破棄されると、 VRMImporterContext が保持する UnityEngine.Object リソースが破棄されます。
            //    このとき破棄されるリソースは、 glTF ファイルには含まれているが VRM の GameObject には割り当てられていないテクスチャなどです。
            //    手順 6. で VRM の GameObject に紐付けたリソースは、ここでは破棄されません。
        }

        private void DestroyVrm(GameObject vrmGameObject)
        {
            // 9. 生成された VRM の GameObject を破棄します。
            //    GameObject を破棄すれば、紐づくリソース (Texture, Material, Mesh, etc) も破棄されます。
            UnityEngine.Object.Destroy(vrmGameObject);
        }
    }
}

このスクリプトを空のゲームオブジェクトに貼り付けて、Animatorを設定しましょう。

後は実行するだけでVRMが読み込まれて、アニメーションまでします。

実行結果

まとめ

非常に簡単にランタイムロードが実装できました。これでPhotonPUN2に対応する準備ができたので、次はオンライン対応させていきます。

+4