MRが楽しい

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

MRTK v2のドキュメントを少しずつ読み解く コンテンツ読み込みの監視

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

MRTKv2のGuidesドキュメント

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

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

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

コンテンツ読み込みの監視

シーン操作の進捗

コンテンツがロードまたはアンロードされると SceneOperationInProgress プロパティは true を返します。
この SceneOperationProgress プロパティを使用して、この操作の進行状況を監視できます。

SceneOperationProgress の値は現在の非同期シーン操作の平均値です。
コンテンツの読み込みの開始時に SceneOperationProgress は 0 になります。
読み込みが完全に完了すると SceneOperationProgress は 1 に設定され、次の操作が行われるまで 1 のままです。
コンテンツシーンの操作のみがこれらのプロパティに影響することに注意してください。

これらのプロパティは、操作に複数のステップが含まれている場合でも、開始から終了までの操作全体の状態を反映します。

IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();

// First do an additive scene load
// SceneOperationInProgress will be true for the duration of this operation
// SceneOperationProgress will show 0-1 as it completes
// 最初に追加のシーンロードを実行します
// SceneOperationInProgress はこの操作中は true になります
// SceneOperationProgress は完了するまでの間に 0-1 を表示します
await sceneSystem.LoadContent("ContentScene1");

// Now do a single scene load
// This will result in two actions back-to-back
// First "ContentScene1" will be unloaded
// Then "ContentScene2" will be loaded
// SceneOperationInProgress will be true for the duration of this operation
// SceneOperationProgress will show 0-1 as it completes
// 単一のシーンのロードを行います
// これにより、以下の2つのアクションが連続して行われます
// 1.最初の「ContentScene1」がアンロードされます
// 2.次に、「ContentScene2」がロードされます
// SceneOperationInProgress はこの操作中は true になります
// SceneOperationProgress は完了するまでの間に 0-1 を表示します
await sceneSystem.LoadContent("ContentScene2", LoadSceneMode.Single);

f:id:bluebirdofoz:20200320092132j:plain

進捗例

SceneOperationInProgress はコンテンツのロード中にアクティビティを一時停止する必要がある場合に役立ちます。

public class FooManager : MonoBehaviour
{
    private void Update()
    {
        IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();

        // Don't update foos while a scene operation is in progress
        // シーン操作の進行中に更新処理を行わない
        if (sceneSystem.SceneOperationInProgress)
        {
            return;
        }

        // Update foos
        // ...
    }
    // ...
}

f:id:bluebirdofoz:20200320092144j:plain

SceneOperationProgress を使用して、進行状況ダイアログを表示できます。

public class ProgressDialog : MonoBehaviour
{
    private void Update()
    {
        IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();

        if (sceneSystem.SceneOperationInProgress)
        {
            DisplayProgressIndicator(sceneSystem.SceneOperationProgress);
        }
        else
        {
            HideProgressIndicator();
        }
    }
    // ...
}

f:id:bluebirdofoz:20200320092155j:plain

アクションによる監視

シーンシステムにはシーンがロードまたはアンロードされるタイミングを知らせるいくつかのアクションが用意されています。
各アクションは、影響を受けるシーンの名前を伝えます。

ロードまたはアンロード操作に複数のシーンが含まれる場合、関連するアクションは影響を受けるシーンごとに1回呼び出されます。
また、これらはロードまたはアンロード操作が完全に完了すると同時に呼び出されます。
このため、OnUnloaded アクションを使用して事後に破棄されたコンテンツを検出するのではなく OnWillUnload アクションを使用して破棄されるコンテンツを検出することをお勧めします。

OnLoaded アクションはすべてのシーンがアクティブ化されて完全にロードされたときにのみ呼び出されます。
OnLoaded アクションを使用して新しいコンテンツを検出および使用しても安全であることが保証されます。

アクション呼び出しタイミング コンテンツ
シーン
照明
シーン
マネージャ
シーン
OnWillLoadContent コンテンツシーンが読み込まれる直前
OnContentLoaded ロード操作の全てのコンテンツシーンが
ロードおよびアクティブ化された後
OnWillUnloadContent コンテンツシーンのアンロード操作の直前
OnContentUnloaded アンロード操作の全てのコンテンツシーンが
完全にアンロードされた後
OnWillLoadLighting 照明シーンが読み込まれる直前
OnLightingLoaded 照明シーンが完全にロードおよび
アクティブ化された後
OnWillUnloadLighting 照明シーンのアンロードの直前
OnLightingUnloaded 照明シーンがアンロードされた後
OnWillLoadScene シーンのロード直前
OnSceneLoaded ロード操作の全てのシーンが
ロードおよびアクティブ化された後
OnWillUnloadScene シーンのアンロードの直前
OnSceneUnloaded シーンが完全にアンロードされた後

アクションの例

以下は更新の代わりに、アクションとコルーチンを使用する進行ダイアログの例です。

public class ProgressDialog : MonoBehaviour
{
    private bool displayingProgress = false;

    private void Start()
    {
        IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();
        sceneSystem.OnWillLoadContent += HandleSceneOperation;
        sceneSystem.OnWillUnloadContent += HandleSceneOperation;
    }

    private void HandleSceneOperation (IEnumerable<string> sceneName)
    {
        // This may be invoked multiple times per frame - once per scene being loaded or unloaded.
        // So filter the events appropriately.
        // これは、フレームごとに複数回呼び出すことができます。
        // シーンのロードまたはアンロードごとに1回。
        // このため、イベントを適切にフィルタリングする必要があります。
        if (displayingProgress)
        {
            return;
        }

        displayingProgress = true;
        StartCoroutine(DisplayProgress());
    }

    private IEnumerator DisplayProgress()
    {
        IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();

        while (sceneSystem.SceneOperationInProgress)
        {
            DisplayProgressIndicator(sceneSystem.SceneOperationProgress);
            yield return null;
        }

        HideProgressIndicator();
        displayingProgress = false;
    }

    // ...
}

f:id:bluebirdofoz:20200320092214j:plain

シーンのアクティブ化を制御する

デフォルトでは、コンテンツシーンはロード時にアクティブになるように設定されています。
シーンのアクティブ化を手動で制御する場合、SceneActivationToken を任意のコンテンツロードメソッドに渡すことができます。
1回の操作で複数のコンテンツシーンがロードされている場合、このアクティベーショントークンはすべてのシーンに適用されます。

IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();

SceneActivationToken activationToken = new SceneActivationToken();

// Load the content and pass the activation token
// コンテンツを読み込み、アクティベーショントークンを渡す
sceneSystem.LoadContent(new string[] { "ContentScene1", "ContentScene2", "ContentScene3" }, LoadSceneMode.Additive, activationToken);

// Wait until all users have joined the experience
// 全てのユーザーがエクスペリエンスに参加するまで待ちます
while (!AllUsersHaveJoinedExperience())
{
    await System.Threading.Tasks.Task.Yield();
}

// Let scene system know we're ready to activate all scenes
// 全てのシーンをアクティブにする準備ができたことをシーンシステムに知らせます
activationToken.AllowSceneActivation = true;

// Wait for all scenes to be fully loaded and activated
// すべてのシーンが完全にロードされてアクティブになるのを待ちます
while (sceneSystem.SceneOperationInProgress)
{
    await System.Threading.Tasks.Task.Yield();
}

// Proceed with experience

f:id:bluebirdofoz:20200320092224j:plain

ロードされているコンテンツの確認

ContentSceneNames プロパティは、インデックスの構築順に利用可能なコンテンツシーンの配列を提供します。
IsContentLoaded(string contentName) を使用して、これらのシーンがロードされているかどうかを確認できます。

IMixedRealitySceneSystem sceneSystem = MixedRealityToolkit.Instance.GetService<IMixedRealitySceneSystem>();

string[] contentSceneNames = sceneSystem.ContentSceneNames;
bool[] loadStatus = new bool[contentSceneNames.Length];

for (int i = 0; i < contentSceneNames.Length; i++)
{
    loadStatus[i] = sceneSystem.IsContentLoaded(contentSceneNames[i]);
}

f:id:bluebirdofoz:20200320092235j:plain