MRが楽しい

MRやVRについて学習したことを書き残す

MRTK v2のドキュメントを少しずつ読み解く シーン移行サービス

本日は MRTKv2 の調査枠です。
MRTKv2 の Guides ドキュメントを少しずつ読み進めていきます。

MRTKv2のGuidesドキュメント

以下のドキュメントを読み進めていきます。
microsoft.github.io

以下のページでは有志による本ドキュメントの日本語翻訳が行われています。
投稿時点でこちらで未翻訳、または著者が興味のある部分について記事にしていきます。
hololabinc.github.io

本記事では以下のページを読み進めます。
microsoft.github.io
f:id:bluebirdofoz:20200212212221j:plain

シーン移行サービス

この拡張機能は以下の処理を簡素化します。
・シーンをフェードアウトし、進行状況インジケーターを表示する。
・シーンをロードしてからフェードインする

シーン操作は SceneSystem サービスによって実行されますが、タスクベースの操作を使用してトランジションを実行できます。
f:id:bluebirdofoz:20200212213443j:plain

拡張機能を有効にする

拡張機能を有効にするには、RegisteredServiceProvider プロファイルを開きます。
[Register a new Service Provider]をクリックして、新しい構成を追加します。
[Component Type]フィールドで、[SceneTransitionService]を選択します。
[Configuration Profile]フィールドで、拡張機能に含まれるデフォルトのシーン遷移プロファイルを選択します。

本プロファイルを利用するには Extensions パッケージをインポートする必要があります。
f:id:bluebirdofoz:20200212213824j:plain

プロファイルオプション

f:id:bluebirdofoz:20200212214006j:plain

Use Default Progress Indicator(デフォルトの進行状況インジケータを使用する)

オンにすると、DoSceneTransition の呼び出し時に、デフォルトの進行状況インジケータープレハブが使用されます。
進行状況インジケータオブジェクトが提供されている場合は、デフォルトでは無視されます。

Use Fade Color(フェードカラーを使用)

チェックすると、移行サービスは移行中にフェードを適用します。
この設定は、サービスの UseFadeColor プロパティを使用して実行時に変更できます。

Fade Color(フェードカラー)

フェード効果の色を制御します。アルファは無視されます。
この設定は、サービスの FadeColor プロパティを使用して、移行前に実行時に変更できます。

Fade Targets(フェードターゲット)

どのカメラにフェード効果を適用するかを制御します。
この設定はサービスの FadeTargets プロパティを介して実行時に変更できます。

設定対象カメラ
Mainメインカメラにフェード効果を適用します
UIUIレイヤー上のカメラにフェード効果を適用します
AllメインカメラとUIカメラの両方に適用されます
CustomSetCustomFadeTargetCameras で提供されるカメラのカスタムセットに適用されます

Fade Out Time/Fade In Time(フェードアウト時間/フェードイン時間)

トランジションの開始/終了時のフェードの持続時間を設定します。
この設定はサービスの FadeOutTime および FadeInTime プロパティを介して実行時に変更できます。

Camera Fader Type(カメラフェーダータイプ)

ICameraFader クラスはカメラにフェード効果を適用するために使用します。
デフォルトの CameraFaderQuad クラスは、クリッププレーンに近いターゲットカメラの前に透明なマテリアルを持つ平面(Quad)をインスタンス化します。
別のアプローチとして、ポストエフェクトシステムを使用する方法もあります。

拡張機能を使用する

カメラがフェードアウトしている間に実行されるタスクを渡すことで、移行サービスを使用します。

シーンシステムタスクの使用

ほとんどの場合、SceneSystem サービスが提供するタスクを使用します。

private async void TransitionToScene()
{
    IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();
    ISceneTransitionService transition = MixedRealityToolkit.Instance.GetService<ISceneTransitionService>();
    // Fades out // Runs LoadContent task // Fades back in
    await transition.DoSceneTransition(
        () => sceneSystem.LoadContent("TestScene1")
    );
}

カスタムタスクの使用

他には、実際にシーンをロードせずにトランジションを実行したい場合があります。

private async void TransitionToScene()
{
    ISceneTransitionService transition = MixedRealityToolkit.Instance.GetService<ISceneTransitionService>();
    // Fades out // Resets scene // Fades back in
    await transition.DoSceneTransition(
        () => ResetScene()
    );
}

private async Task ResetScene()
{
    // Go through all enemies in the current scene and move them back to starting positions
    // 現在のシーン内のすべての敵を無視し、それらを開始位置に戻します
} 

または SceneSystem サービスを使用せずにシーンをロードすることもできます。

private async void TransitionToScene()
{
    ISceneTransitionService transition = MixedRealityToolkit.Instance.GetService<ISceneTransitionService>();
    // Fades out // Loads scene using Unity's scene manager // Fades back in
    await transition.DoSceneTransition(
        () => LoadScene("TestScene1")
    );
}

private async Task LoadScene(string sceneName)
{
    AsyncOperation asyncOp = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
    while (!asyncOp.isDone)
    {
        await Task.Yield();
    }
} 

複数のタスクを使用する

次の順序で実行される複数のタスクを提供することもできます。

private async void TransitionToScene()
{
    IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();
    ISceneTransitionService transition = MixedRealityToolkit.Instance.GetService<ISceneTransitionService>();
    // Fades out // Sets time scale to 0 // Fades out audio to 0
    // Loads TestScene1 // Fades in audio to 1 // Sets time scale to 1 // Fades back in
    await transition.DoSceneTransition(
        () => SetTimescale(0f),
        () => FadeAudio(0f, 1f),
        () => sceneSystem.LoadContent("TestScene1"),
        () => FadeAudio(1f, 1f),
        () => SetTimescale(1f)
    );
}

private async Task SetTimescale(float targetTime)
{
    Time.timeScale = targetTime;
    await Task.Yield();
}

private async Task FadeAudio(float targetVolume, float duration)
{
    float startTime = Time.realtimeSinceStartup;
    float startVolume = AudioListener.volume;
    while (Time.realtimeSinceStartup < startTime + duration)
    {
        AudioListener.volume = Mathf.Lerp(
            startVolume, targetVolume,
            Time.realtimeSinceStartup - startTime / duration
        );
        await Task.Yield();
    }
    AudioListener.volume = targetVolume;
} 

進行状況インジケーターの使用

進行状況インジケーターは、IProgressIndicatorインターフェイスを実装するものです。
これはインジケーターを以下の形式にすることができます。
・スプラッシュスクリーン
・3D tagalong のロードインジケータ
・移行の進行状況に関するフィードバックを提供するその他の形式

SceneTransitionService プロファイルで UseDefaultProgressIndicator がチェックされている場合、トランジションが開始されると進行状況インジケーターがインスタンス化されます。
遷移の間、このインジケーターの Progress および Message プロパティは、そのサービスの SetProgressValue および SetProgressMessage メソッドを介してアクセスできます。

private async void TransitionToScene()
{
    IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();
    ISceneTransitionService transition = MixedRealityToolkit.Instance.GetService<ISceneTransitionService>();
    ListenToSceneTransition(sceneSystem, transition);
    await transition.DoSceneTransition(
        () => sceneSystem.LoadContent("TestScene1")
    );
}

private async void ListenToSceneTransition(IMixedRealitySceneSystem sceneSystem, ISceneTransitionService transition)
{
    transition.SetProgressMessage("Starting transition...");
    while (transition.TransitionInProgress)
    {
        if (sceneSystem.SceneOperationInProgress)
        {
            transition.SetProgressMessage("Loading scene...");
            transition.SetProgressValue(sceneSystem.SceneOperationProgress);
        }
        else
        {
            transition.SetProgressMessage("Finished loading scene...");
            transition.SetProgressValue(1);
        }
        await Task.Yield();
    }
} 

または、 DoSceneTransition を呼び出すときに、オプションの progressIndicator 引数を使用して独自の進行状況インジケーターを提供できます。
これにより、デフォルトの進行状況インジケータが上書きされます。