1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Record and Play を用いて、Unityのゲームオブジェクトの動きをデバイス内で保存、再生する

Posted at

はじめに

いわゆるvTuberのようにアバターをVR内で動かすとき、動きを保存して後で再生したいことは多いです。そういうシーン内モーションキャプチャーのためのUnityアセットは既にいくつか公開されていますが、Unityエディター内でしかキャプチャーしたデータを保存できない、という問題がありました。

それに対して今回紹介するRecord and Playは、ビルドしたアプリ内でゲームオブジェクトの動きを記録してデータファイルを生成し、保存することが可能です。私はVive Focus Plus内でモーションキャプチャーをテストしましたが、無事デバイス内のフォルダに記録ファイルを保存できました。

image.png

今回は、その方法を紹介します。なお、以下の内容はごく基本的なものだけなので、より詳しいことは公式ページ.を参考にしてください。

記録を取る

記録を取るには、まずRecorderというScriptable Objectを生成します。スクリプトからも作れますが、私はエディター内のメニュー(Create->RecordAndPlay->Recorder)で作ってます。

image.png

次に、作ったRecorderに対してトラッキングしたいゲームオブジェクトを指定します。下の例のように、オブジェクトをListで指定し、SubjectBehaviour.Buildを使って一つ一つをrecorderに登録します。VRモーションキャプチャーなら、HMDやコントローラに相当するものを指定すればよいでしょう。

RecorderManager.cs
using System.Collections.Generic;
using UnityEngine;
using EliCDavis.RecordAndPlay.Record;
using EliCDavis.RecordAndPlay;
using EliCDavis.RecordAndPlay.IO;
using EliCDavis.RecordAndPlay.Playback;

public class RecorderManager : MonoBehaviour, IActorBuilder
{
    [SerializeField] private Recorder recorder;
    [SerializeField] List<GameObject> trackedObjects;

    void Start(){
        foreach (var obj in trackedObjects)
        {
            SubjectBehavior.Build(obj, recorder);
        }
    }
}

記録を取るときは、recorder.Start();で開始し、終了する際はRecording myRecording = recorder.Finish(); で記録結果をRecording型の変数に保存します。ファイルに保存するときは、ストリームを作ってPackager.Packageメソッドで保存します。例えば、こういう感じです。

RecorderManager.cs
//上に追加
    public void StartRecording()
    {
        recorder.Start();
    }

    public void StopRecording()
    {
        Recording myRecording = recorder.Finish();
        var fileName = string.Format("{0}/demo.rap", Application.persistentDataPath);
        using (FileStream fs = File.Create(fileName))
        {
            myRecording.RecordingName = "Demo";
            Packager.Package(fs, myRecording);
        }
    }

記録を読みだして再生する

ファイルから記録を読み出すときは、Unpackager.Unpackageメソッドを使います。下では、recordingという変数に読み込んだデータを保存します。あとPlaybackBehaviour.Buildを使って、プレイバックのための変数myPlaybackBehaviorを準備します。このさい、Unpackageしたものを保存しているrecording、actor builderを持っているクラス、Custom Event handlerを持っているクラス、ループの有無を指定します。

actor builderというのは、保存したゲームオブジェクトの動きを再現するActorを作るためのクラスで、IActorBuilderを継承し、Buildというメソッドを実装している必要があります。Buildメソッドは、Actorをインスタンス化するときに使うので、後ほどこのクラス内で定義するのでthisにしました。Custom Event handlerについては、今回は使わないのでnullにしました。

RecorderManager.cs
//上に追加
   void LoadRecording(){
        FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
        var recording = Unpackager.Unpackage(fs)[0];
        myPlaybackBehavior = PlaybackBehavior.Build(recording,this,null,false);
   }

それでは、次にBuildメソッドを指定します。これは、記録されたゲームオブジェクトに対応するActorを指定するために呼び出されます。その際、記録されたゲームオブジェクトの名前などがメソッドに渡されるので、以下の例ではそれを最初に指定したトラッキング対象のゲームオブジェクトの名前と比較して、一致していればnew Actor()でActorをインスタンス化して、それへの参照を返却値として渡すようにしました。

RecorderManager.cs
//上に追加
    public Actor Build(int subjectId, string subjectName, Dictionary<string, string> metadata)
    {
        foreach(var ob in trackedObjects)
        {
            if (subjectName == ob.name)
            {
                var actor = new Actor(ob);
                return actor;
            }
        }
        throw new System.Exception("subject for actor not found");
    }

ここまで準備できたら、あとはmyPlaybackBehavior.Play()再生するだけです。Actorを作る際に指定したゲームオブジェクトがPLAYBACK OBJECTというゲームオブジェクトの下に生成(あるいは移動)され、記録した通りに動きます。

RecorderManager.cs
//上に追加
    public void PlayRecording()
    {
        myPlaybackBehavior.Play();
    }
1
4
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
1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?