5
0

More than 1 year has passed since last update.

【CRI】Asset Support Add-onを使ってCRIの音・動画をUnityアセットとして扱う

Last updated at Posted at 2022-12-19

この記事は、サムザップ Advent Calendar 2022 の12/19の記事です。

概要

2022年5月頃にCRI・ミドルウェア社が開発したCRIWARE Unity SDKに、Asset Support Add-onが新しく追加されました。このアドオンには、CRI関連の音声や動画データをUnityアセットとして扱えるようにするCRI Assetsと、UnityのAddressable Assets System(以下AAS)に対応したCRI Addressablesという2つの機能が追加されています。
本記事では、それらの機能について紹介できればと思います。

CRI関連データのインポート

Unityアセットとして扱えるCRI関連のデータとインポート後に付与されるコンポーネントは以下になります

ファイル種別 概要 インポート後に付与されるコンポーネント
ACFファイル 全体設定ファイル CriAtomAcfAsset
ACBファイル 音声キューシートのバイナリファイル CriAtomAcbAsset
AWBファイル 音声ストリーミング再生用の波形データのバイナリファイル CriAtomAwbAsset(CriAssetBaseをただ継承しているだけなので、ドキュメントは無し)
USMファイル Sofdec動画のバイナリファイル CriManaUsmAsset

上記のファイルをUnityプロジェクトのStreaming Assetsフォルダ以外のフォルダに追加すると、インポートの処理が走りそれぞれのUnityアセットが生成されます。

例えば、ACBファイルだとCriAtomAcbAssetクラスのScriptableObjectが生成されます。
同名のACBファイルをAWBファイルを一緒に追加すると、ACBアセットにAWBアセットが紐付けされた状態でインポートされます。ACBアセットにAWBアセットが紐付いていると、ACBアセットをロードすることでAWBアセットも自動でロードされストリーミング再生ができるようになります。
また、インポートされたACBアセットは、Inspectorタブからプレビュー再生することもできます。
acb_inspector.png

ビルド時にアセットの実データをどこに配置するかの設定

CRI関連ファイルのUnityアセットが生成されたら、DeployTypeというプロパティでビルド時に生成するアセットの実データ(ACBファイル、AWBファイルなどのバイナリデータ)をどこに配置するかという設定をします。
デフォルトで選択できる設定は以下になります。

ファイル種別 概要
StreamingAssets StreamingAssetに配置する
OnMemory アセットそのものの中に配置する(AWBファイルは、ストリーミング再生用のデータなので取り扱えない。)
Addressables (Remote) AASで設定したリモートデータ用のパス
Addressables (Local) AASで設定したローカルデータ用のパス

OnMemoryを指定したアセットをロードするとデータは即メモリに展開されるため、ストリーミング再生用のデータを扱うAWBファイルに対しては、OnMemoryを選択できず、AWBファイルを配信用のデータとする場合はAddressables (Remote)を指定することになります。
AASを使わずにAWBファイルを配信用データとして扱いたい場合は、DeployTypeを拡張して独自の実データの取り扱いやロード時の挙動を定義することもできます。1

音のロードと再生

DeployTypeをStreamingAssetsにしたACBアセットをロード及び再生する実装は以下のようになります。
ビルドすると、StreamingAssetsフォルダにACBファイル及びAWBファイルがそのまま配置されるので、ロードと再生は従来の実装と変わらないです。

using CriWare;
using CriWare.Assets;
using System.Threading.Tasks;

public class SoundPlayTest : MonoBehavior
{
    [SerializeField] private Button _playButton;

    private CriAtomExPlayer _player;

    private async void Awake()
    {
        _player = new CriAtomExPlayer();

        _playButton.onClick.AddListener(async () =>
        {
            CriAtomExAcb acb = await LoadAcbAssetFromStreamingAssets("acbFileName", "awbFileName")
            PlayAcb(acb, 1);
        });
    }

    /// <summary>
    /// StreamingAssetsからACBを非同期ロードする
    /// </summary>
    private async Task<CriAtomExAcb> LoadAcbAssetFromStreamingAssets(string acbFileName, string awbFileName)
    {
        string acbPath = $"{CriWare.Common.streamingAssetsPath}/{acbFileName}";
        string awbPath = $"{CriWare.Common.streamingAssetsPath}/{awbFileName}"; 

        // ACBアセットのStreamingAssetsからのロード
        CriAtomExAcbLoader loader = CriAtomExAcbLoader.LoadAcbFileAsync(null, acbPath, awbPath);

        await new WaitUntil(() =>
        {
            var status = loader.GetStatus();
            return status == CriAtomExAcbLoader.Status.Complete
                || status == CriAtomExAcbLoader.Status.Error;
        });

        if (loader.GetStatus() == CriAtomExAcbLoader.Status.Complete)
        {
            return loader.MoveAcb();
        }

        return null;
    }

    /// <summary>
    /// ACBを再生する
    /// </summary>
    private CriAtomExPlayback PlayAcb(CriAtomExAcb acb, int cueId, float volume = 1.0f)
    {
        // プレイヤーへのキューの設定
        player.SetCue(acb, cueId);
        player.SetVolume(volume);

        // 再生
        CriAtomExPlayback playBack = player.Start();

        return playBack;
    }
}

DeployTypeをAddressables (Remote)にしたACBアセットをロード及び再生する実装は以下のようになります。
注意するところとしては、カタログファイルロード完了後に、カタログファイル内のCRIアセット向けの情報を更新する必要があります。2

using CriWare;
using CriWare.Assets;
using System.Threading.Tasks;

public class SoundPlayTest : MonoBehavior
{
    [SerializeField] private Button _playButton;

    private CriAtomExPlayer _player;

    private async void Awake()
    {
        _player = new CriAtomExPlayer();

        _playButton.onClick.AddListener(async () =>
        {
            CriAtomExAcb acb = await LoadAcbFromAddressable("acbAddress");
            PlayAcb(acb, 1);
        });

        // リモートカタログの有無を確認してAddressablesを初期化
		var catalogs = await Addressables.CheckForCatalogUpdates().Task;
		if (catalogs.Count > 0)
		{
            await Addressables.UpdateCatalogs(catalogs).Task;
        }
		else
        {
			await Addressables.InitializeAsync().Task;
        }

		// カタログロード完了後に、カタログ内のCriAddressables向けの情報を修正する
		// この処理を呼ぶことによってAddressables.GetDownloadSizeAsync等が正しい結果を返すようになる
		CriWare.Assets.CriAddressables.ModifyLocators();
    }

    /// <summary>
    /// Addressable経由でACBを非同期ロードする
    /// </summary>
    private async Task<CriAtomExAcb> LoadAcbFromAddressable(string address)
    {
        // ACBアセットのAddressableからのロード
        var acbAsset = await Addressables.LoadAssetAsync<CriAtomAcbAsset>(address);
        if (acbAsset.Loaded == false)
        {
            // ACBアセットのキューシートのロード
            acbAsset.LoadAsync();
            await new WaitUntil(() => acbAsset.Loaded || acbAsset.Status == CriAtomExAcbLoader.Status.Error);
        }

        if (acbAsset.Loaded)
        {
            return acbAsset.Handle;
        }

        return null;
    }

    /// <summary>
    /// ACBを再生する
    /// </summary>
    private CriAtomExPlayback PlayAcb(CriAtomExAcb acb, int cueId, float volume = 1.0f)
    {
        // プレイヤーへのキューの設定
        player.SetCue(acb, cueId);
        player.SetVolume(volume);

        // 再生
        CriAtomExPlayback playBack = player.Start();

        return playBack;
    }
}

動画の再生

スクリプトからUSMアセットを指定して再生する際は、CriManaMovieControllerForAssetというコンポーネントを使います。
CriManaMovieControllerForAssetでは、RenderTargetプロパティで描画対象種別をRendererコンポーネントにするかGraphicコンポーネントにするかを選択できます。
Graphicを選択した場合は、既存のCriManaMovieControllerForUIと同じ描画方法になります。
CriManaMovieControllerForUIと違う点としては、ループの設定やアディティブムービーとして再生するかの設定などがUSMアセット側が持つようになったことで無くなっています。

DeployTypeをStreamingAssetsにしたUSMアセットをロード及び再生する実装は以下のようになります。
ビルドすると、StreamingAssetsフォルダにUSMファイルがそのまま配置されるので、USMファイルの設定と再生は従来の実装とほぼ変わらないです。

using CriWare;
using CriWare.Assets;
using System.Threading.Tasks;

public class MoviePlayTest : MonoBehavior
{
    [SerializeField] private Button _playButton;

    [SerializeField] private CriManaMovieControllerForAsset _movieController;

    private async void Awake()
    {
        _playButton.onClick.AddListener(async () =>
        {
            SetUsmFromStreamingAssets("usmFileName");
            PlayUsm();
        });
    }

    /// <summary>
    /// StreamingAssetsフォルダのUSMファイルをプレイヤーに設定する
    /// </summary>
    private void SetUsmFromStreamingAssets(string usmFileName)
    {
        // プレイヤーにUSMファイルをセットする
        _movieController.player.SetFile(null, $"{CriWare.Common.streamingAssetsPath}/{usmFileName}");
    }

    /// <summary>
    /// USMを再生する
    /// </summary>
    private void PlayUsm()
    {
        _movieController.Play();
    }
}

DeployTypeをAddressables (Remote)にしたUSMアセットのロードと再生の実装は以下のようになります。
CriMana.Playerに、CriManaUsmAssetをプレイヤーに設定する拡張メソッドが用意されているので、それを使うのが便利です。

using CriWare;
using CriWare.Assets;
using System.Threading.Tasks;

public class MoviePlayTest : MonoBehavior
{
    [SerializeField] private Button _playButton;

    [SerializeField] private CriManaMovieControllerForAsset _movieController;

    private async void Awake()
    {
        _playButton.onClick.AddListener(async () =>
        {
            await LoadAndSetUsmAssetFromAddressable("usmAddress");
            PlayUsm();
        });

        // リモートカタログの有無を確認してAddressablesを初期化
		var catalogs = await Addressables.CheckForCatalogUpdates().Task;
		if (catalogs.Count > 0)
		{
            await Addressables.UpdateCatalogs(catalogs).Task;
        }
		else
        {
			await Addressables.InitializeAsync().Task;
        }

		// カタログロード完了後に、カタログ内のCriAddressables向けの情報を修正する
		// この処理を呼ぶことによってAddressables.GetDownloadSizeAsync等が正しい結果を返すようになる
		CriWare.Assets.CriAddressables.ModifyLocators();
    }

    /// <summary>
    /// Addressable経由でUSMアセットを非同期ロードしプレイヤーに設定する
    /// </summary>
    private async Task<CriManaUsmAsset> LoadAndSetUsmAssetFromAddressable(string address)
    {
        // USMアセットのAddressableからのロード
        var usmAsset = await Addressables.LoadAssetAsync<CriManaUsmAsset>(address);

        // プレイヤーにUSMアセットをセットする
        _movieController.player.SetAsset(usmAsset);
    }

    /// <summary>
    /// USMを再生する
    /// </summary>
    private void PlayUsm()
    {
        _movieController.Play();
    }
}

まとめ

CRI関連データをアセットバンドルやAddressableとして扱うとなると、拡張子に.bytesを付けてバイナリデータとして配信してダウンロード後に元の形式のファイルとしてPersistantDataPathなどに書き込みを行ったり、Addressableの場合は独自にプロバイダーを実装したりする必要がありましたが、Asset Support Add-onを使うとこれらの必要がなくなります。

AASとCRIWAREを使おうと考えている方は、Asset Support Add-onの導入も考えてみても良いかもしれません。

明日は、@chrno001さんの記事です。

注釈

  1. https://game.criware.jp/manual/unity_plugin/latest/contents/cri4u_samples_addon_asset_scene07.html

  2. https://game.criware.jp/manual/unity_plugin/latest/contents/cri4u_samples_addon_asset_scene02.html#cri4u_samples_addon_asset_scene02_programs

5
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
5
0