じゅころぐAR

ARのブログ

ARCoreのRecording and Playback APIをAR Foundationで使う

Google I/O 2021にて、ARCoreの新機能 Recording and Playback API が発表・リリースされました。

developers.google.com

AR Foundationの最新バージョンが即座に対応しており、簡単に使えてARのテストに便利な機能なので、サクサクサクっと試します。

サンプルを動かす

Recording and Playback APIは、周囲の環境を映した動画を録画しておき、再生することでARのテストができる機能です。
ARCore 1.24で追加されており、対応するAR Foundationのバージョンは4.2 preview7 以降となります。

AR Foundation Samplesにすぐに動かせるサンプルシーンがあるので、mainブランチから最新バージョンを取得します。

README.mdを読むと、AR Foundation 4.2を使うにはUnity 2021.2が必要となっていますので、Unity Hubで2021.2.0a17をインストールしました。

f:id:jyuko49:20210526233448p:plain

AR Foundation SamplesをUnityで開いてみると、"Assets" > "Scenes" > "ARCore" に "ARCoreSessionRecoding"というシーンがあります。
こちらのシーンを開きます。

f:id:jyuko49:20210526234009p:plain

シーンの構成を見てみると、AR Foundationの基本構成となる"AR Session"、"AR Session Origin"が配置されています。
ポイントになるのは、"AR Session"にアタッチされている"ARCoreSessionRecorder"で、こちらにRecordingとPlaybackの処理が書かれています。中身の処理は後で確認することにして、まずは動かしてみましょう。

ビルドの際に、プラットフォームをAndroidに切り替えるのと、ビルド対象のシーンが "ARCoreSessionRecoding"になっているか注意してください。

f:id:jyuko49:20210526235847p:plain

Androidの実機で動かします。私はPixel 3aを使っています。
画面上部にボタンのUIが表示されており、[Start recording]で録画が開始されます。そのまま周囲の環境を映して、[Stop recording]を行うと動画が保存されます。

f:id:jyuko49:20210527000010p:plain

保存した動画は[Start playback]で再生されます。

再生した動画でも、録画時と同じように平面や点群(Point Cloud)が検出できています。
また、Playbackの動作を確認するため、サンプルシーンを一部修正して、画面タップで平面にキューブを置く処理を追加しています。赤いキューブはRecording時ではなく、Playback時に画面タップした位置に移動しました。

Recodingされた動画を確認する

Playbackの結果は一見すると、平面や点群も映像として録画されているように見えます。
そこで、Android Transferで保存されている動画をPCに転送して、確認してみます。

保存された動画は、arcore-session.mp4というファイル名で保存されています。

f:id:jyuko49:20210527005109p:plain

こちらを再生してみると、カメラアプリで普通に録画したのと同じような風景だけの動画になっています。
ARCoreのドキュメントからDepthの情報は動画に含まれているようですが、平面や点群はPlayback時に検知・表示されていることになります。

f:id:jyuko49:20210526231422p:plain

Playbackの動作を確認する

平面や点群が動画には保存されていないことがわかったので、"AR Plane Manager"と"AR Point Cloud Manager"のPrefabに適用されているマテリアルを変更して、色などを変えてみます。

f:id:jyuko49:20210527010742p:plain

変更がPlaybackに反映されていますね。

続いて、AR Camera Backgroundに、カラーをネガティブ反転するマテリアルを適用してみます。

こちらもしっかり適用されています。

AR Sessionからのフィードバックを受けて行う処理(平面検知、点群取得、Hittest、カメラ画像やデプスの取得など)は、すべてPlaybackで再現できており、Playbackで実行するために既存の処理を変更する必要はありません。Playbackボタンを押すだけです。

APIの使い方を確認する

最後に、ARCoreSessionRecorderのスクリプトからAPIの使い方を見てみます。

Recording and Playbackは、"AR Session"で使用する情報を録画して再生する機能なので、"ARSession"が必須になります。

[RequireComponent(typeof(ARSession))]

保存するmp4ファイルのパスはAwake()で定義されており、固定のファイル名になっています。 そのため、サンプルではRecordingを複数回行うと、動画が上書きされてしまいます。

m_Mp4Path = Path.Combine(Application.persistentDataPath, "arcore-session.mp4");

PCに転送できるにしても、実用性を考えると複数の動画を保存しておきたいので、保存時ファイル名にタイムスタンプを付与するなどして上書きされないように変更して使った方がよさそうです。

また、録画の設定として、保存先のファイル名だけでなく、画面の向きが必要なようです。このあたりはサンプルそのままの実装でも問題ないと思います。

static int GetRotation() => Screen.orientation switch
        {
            ScreenOrientation.Portrait => 0,
            ScreenOrientation.LandscapeLeft => 90,
            ScreenOrientation.PortraitUpsideDown => 180,
            ScreenOrientation.LandscapeRight => 270,
            _ => 0
        };

ここからがAPIを呼び出す部分ですが、ARCoreの機能なのでUNITY_ANDROIDのみの処理としてから、"ARCoreSessionSubsystem"を参照しています。

現在Recordingを行っているか、Playbackを行っているかは.recordingStatus.playbackStatusのプロパティで判別しています。

#if UNITY_ANDROID
            if (m_Session.subsystem is ARCoreSessionSubsystem subsystem)
            {
                var session = subsystem.session;
                if (session == null)
                    return;

                var playbackStatus = subsystem.playbackStatus;
                var recordingStatus = subsystem.recordingStatus;
...

Recording開始時の処理です。

if (playbackStatus != ArPlaybackStatus.Finished && GUILayout.Button("Start recording"))
{
    using (var config = new ArRecordingConfig(session))
    {
        config.SetMp4DatasetFilePath(session, m_Mp4Path);
        config.SetRecordingRotation(session, GetRotation());
        var status = subsystem.StartRecording(config);
        Log($"StartRecording to {config.GetMp4DatasetFilePath(session)} => {status}");
    }
}

ArRecordingConfigを作成して、保存先のファイルパス、画面の向きをセットしています。
設定したconfigをsubsystem.StartRecording(config)の形で使っており、このメソッドがARCoreのRecording APIで録画を開始する処理になりそうです。

停止時の処理はというと、subsystem.StopRecording()を呼ぶだけでよさそうです。保存先のファイルパスは開始時にconfigで渡しているので、停止時には渡していません。

if (recordingStatus.Recording() &&
    GUILayout.Button("Stop recording"))
    {
        var status = subsystem.StopRecording();
        Log($"StopRecording() => {status}");
        ...

次は、Playback開始時の処理です。

if (File.Exists(m_Mp4Path) && GUILayout.Button("Start playback"))
{
    var status = subsystem.StartPlayback(m_Mp4Path);
    Log($"StartPlayback({m_Mp4Path}) => {status}");
}

subsystem.StartPlayback()に保存してある動画のパスを渡しているだけですね。

停止も停止用のメソッドを呼ぶだけです。

if (playbackStatus.Playing() &&
    !recordingStatus.Recording() &&
    GUILayout.Button("Stop playback"))
{
    var status = subsystem.StopPlayback();
    Log($"StopPlayback() => {status}");
}

かなり簡単に使えそうですね。

まとめ

Recording and Playback APIを試してみました。

ARは周囲の環境(ロケーション)に大きく依存するため、実際にその場所に行って歩き回らなくても、一度録画してしまえば机上で何度でもテストできるというのは非常に有益です。
実際に使ってみるとかなり便利ですし、会場や現地に行かないと体験できない等、特定のロケーションで実施するARの開発であればさらに威力を発揮します。

使い方が難しくなく、簡単に導入できるのもよいです。

おわりに

同時に公開されたRaw Depthもそうですけど、ARCoreのアップデートは派手さはないものの、既存デバイスも対象として基本性能がベースアップしている感じで好感が持てますね。
目立った新機能がない分、実験的な機能はNianticのSDKに継承されてるような雰囲気もあるので、そちらの続報も待ちたいところです。

あと、AR FoundationはARCore/ARKitと連携取れてて、新機能のリリースとほぼ同時にサポートされるのでよいですね。