この記事はVR法人HIKKYのアドベントカレンダー2日目の記事です。
この記事ではVRMとVRMAファイルをランライムで バイナリとして 読み込み、シーン上の GameObject に適用してアニメーション再生をさせるまでの実装方法を紹介します。
VRM/VRMA とは
VRMとは人型の3Dモデルをゲームやアプリケーションでランライムでも取り扱えるように仕様化されたファイル形式です。
一方、VRMAとはそのVRMで再生することを想定してアニメーションを記述したファイルです。UnityのAnimationClip と違って、VRM同様ランライムで読み込み・再生が可能です。
素材
記事を書く上で以下のVRMとVRMAをお借りしました。
実装
VRMとVRMAをUnityのシーン上にて最短で試そうとすると以下の様な実装になるのではと思います。Resourcesに配置したファイルを直接読み込んでいます。
環境は以下です
Unity: 6000.0.62f1
UniVRM: v0.130.1
using System.Threading;
using System.Threading.Tasks;
using UniGLTF;
using UnityEngine;
using UniVRM10;
public class EntryPoint : MonoBehaviour
{
// Resources/Vketchan_v1.6_MToon_blendshape.vrm.bytes というファイルとして置いている
[SerializeField] string _vrmResourcesPath = "Vketchan_v1.6_MToon_blendshape.vrm";
// Resources/VRMA_02.vrma.bytes というファイルとして置いている
[SerializeField] string _vrmaResourcesPath = "VRMA_02.vrma";
Vrm10Instance _vrmInstance;
RuntimeGltfInstance _vrmaInstance;
async void Start()
{
// vrmの読み込み
var vrmTextAsset = Resources.Load<TextAsset>(_vrmResourcesPath);
_vrmInstance = await Vrm10.LoadBytesAsync(vrmTextAsset.bytes,
canLoadVrm0X: true,
showMeshes: true,
ct: destroyCancellationToken);
// vrmaを読み込んでvrmに適用
var vrmaTextAsset = Resources.Load<TextAsset>(_vrmaResourcesPath);
using var vrmaGlftData = new GlbLowLevelParser(_vrmaResourcesPath, vrmaTextAsset.bytes).Parse();
var vrmAnimationData = new VrmAnimationData(vrmaGlftData);
_vrmaInstance = await ApplyAnimationAsync(_vrmInstance, vrmAnimationData, destroyCancellationToken);
// アニメーション再生
var vrmaAnimation = _vrmaInstance.GetComponent<Animation>();
vrmaAnimation.Play();
}
void OnDestroy()
{
_vrmaInstance.Dispose();
_vrmaInstance = null;
_vrmInstance.DisposeRuntime();
_vrmInstance = null;
}
static async Task<RuntimeGltfInstance> ApplyAnimationAsync(Vrm10Instance vrm,
VrmAnimationData animationData, CancellationToken cancel)
{
if (vrm == null || animationData == null)
{
return null;
}
using var loader = new VrmAnimationImporter(animationData);
var vrma = await loader.LoadAsync(new ImmediateCaller());
// vrmにvrmaのアニメーションを適用
var animationInstance = vrma.GetComponent<Vrm10AnimationInstance>();
animationInstance.ShowBoxMan(false);
vrm.Runtime.VrmAnimation = animationInstance;
return vrma;
}
}
結果
解説
Resourcesからロードする際バイナリで読み込むには.vrmの拡張子のままだとダメで、.bytes などの拡張子として追加する必要があります。その上で Resources.Load に渡す文字列では .bytes の拡張子部分が不要なのでややこしいですね。
あとは vrm のパスでなくバイナリから読み込む方針で実装しているので、サンプルでは見慣れないクラスを駆使して読み込んでいきます。
animationInstance.ShowBoxMan(false) を呼び出さないと下の画像のように白い人型(BoxManというらしい)が表示されたままになりますのでVRMAをVRMと合わせて表示する際は注意して下さい。

あとは不要になったタイミングでVRMとVRMAのインスタンスは両方ちゃんと明示的に破棄しましょう。
