Tutorial: Schnittstellen und benutzerdefinierte Modelle

In diesem Tutorial lernen Sie Folgendes:

  • Hinzufügen des Mixed Reality-Toolkits zum Projekt
  • Verwalten des Modellzustands
  • Konfigurieren von Azure Blob Storage für die Modellerfassung
  • Hochladen und Verarbeiten von Modellen für das Rendering

Voraussetzungen

Erste Schritte mit dem Mixed Reality-Toolkit (MRTK)

Das Mixed Reality-Toolkit (MRTK) ist ein plattformübergreifendes Toolkit für die Mixed Reality-Entwicklung. Wir verwenden die MRTK-Version 2.8.3 aufgrund ihrer Interaktions- und Visualisierungsfunktionen.

Der offizielle Leitfaden zum Importieren des MRTK enthält einige Schritte, die wir nicht ausführen müssen. Es sind nur die folgenden drei Schritte erforderlich:

  • Importieren Sie „Mixed Reality Toolkit/Mixed Reality Toolkit Foundation“, Version 2.8.3 über das Mixed Reality Feature Tool (MRTK importieren) in Ihr Projekt.
  • Führen Sie den Konfigurations-Assistenten des MRTK (MRTK konfigurieren) aus.
  • Fügen Sie das MRTK zur aktuellen Szene (Zu Szene hinzufügen) hinzu. Verwenden Sie hier arrMixedRealityToolkitConfigurationProfile anstelle des vorgeschlagenen Profils im Tutorial.

Importieren der in diesem Tutorial verwendeten Ressourcen

In diesem Kapitel implementieren wir zunächst ein grundlegendes Muster vom Typ „Model View Controller“ für einen Großteil des behandelten Materials. Bei der Modellkomponente (Model) des Musters handelt es sich um den Azure Remote Rendering-spezifischen Code und um die Zustandsverwaltung für Azure Remote Rendering. Die Ansichts-/Controllerkomponente (View und Controller) des Musters wird mithilfe von MRTK-Ressourcen und einigen benutzerdefinierten Skripts implementiert. Das Modell in diesem Tutorial kann ohne die hier implementierte Ansichts-/Controllerkomponente (View/Controller) verwendet werden. Dank dieser Trennung können Sie den Code in diesem Tutorial ganz einfach in Ihre eigene Anwendung integrieren, wo er die Ansichts-/Controllerkomponente (View/Controller) des Entwurfsmusters übernimmt.

Mit der Einführung des MRTK stehen mehrere Skripts, Prefabs und Ressourcen zur Verfügung, die nun dem Projekt hinzugefügt werden können, um Interaktionen und visuelles Feedback zu unterstützen. Diese als Tutorialressourcen bezeichneten Ressourcen werden in einem Unity-Ressourcenpaket gebündelt, das im GitHub-Repository für Azure Remote Rendering in „\Unity\TutorialAssets\TutorialAssets.unitypackage“ enthalten ist.

  1. Klonen Sie das Git-Repository Azure Remote Rendering, oder laden Sie es herunter, und extrahieren Sie die ZIP-Datei an einem bekannten Speicherort.
  2. Wählen Sie in Ihrem Unity-Projekt Assets > Import Package > Custom Package („Ressourcen“ > „Paket importieren“ > „Benutzerdefiniertes Paket“) aus.
  3. Navigieren Sie im Datei-Explorer zu dem Verzeichnis, in dem Sie das Azure Remote Rendering-Repository geklont oder entzippt haben, und wählen Sie anschließend die .unitypackage unter Unity –> TutorialAssets –> TutorialAssets.unitypackage aus.
  4. Wählen Sie die Schaltfläche Import (Importieren) aus, um die Paketinhalte in Ihr Projekt zu importieren.
  5. Wählen Sie im Unity-Editor auf der oberen Menüleiste Mixed Reality Toolkit > Utilities > Upgrade MRTK Standard Shader for Lightweight Render Pipeline („Mixed Reality-Toolkit“ > „Hilfsprogramme“ > „MRTK-Standardshader für einfache Renderpipeline upgraden“) aus, und folgen Sie den Anweisungen, um ein Shaderupgrade durchzuführen.

Nachdem das MRTK und die Tutorialressourcen eingerichtet wurden, überprüfen Sie, ob das richtige Profil ausgewählt ist.

  1. Wählen Sie in der Szenehierarchie das Spielobjekt (GameObject) MixedRealityToolkit aus.
  2. Ändern Sie das Konfigurationsprofil im Inspektor unter der Komponente MixedRealityToolkit in ARRMixedRealityToolkitConfigurationProfile.
  3. Drücken Sie zum Speichern der Änderungen STRG+S.

Durch diesen Schritt wird das MRTK in erster Linie mit den standardmäßigen HoloLens 2-Profilen konfiguriert. Die bereitgestellten Profile sind wie folgt vorkonfiguriert:

  • Der Profiler ist deaktiviert. (Drücken Sie 9, um ihn ein- oder auszuschalten, oder sagen Sie „Profiler anzeigen/ausblenden“ auf dem Gerät.)
  • Der Anvisier-Cursor ist deaktiviert.
  • Unity-Mausklicks sind aktiviert, um mit der Maus auf Elemente der MRTK-Benutzeroberfläche klicken zu können, anstatt die simulierte Hand zu verwenden.

Hinzufügen des App-Menüs

Die meisten der Ansichtscontroller in diesem Tutorial arbeiten nicht mit konkreten Klassen, sondern mit abstrakten Basisklassen. Dieses Muster bietet mehr Flexibilität und ermöglicht es uns, die Ansichtscontroller für Sie bereitzustellen und Sie trotzdem mit dem Azure Remote Rendering-Code vertraut zu machen. Für die Klasse RemoteRenderingCoordinator wurde der Einfachheit halber keine abstrakte Klasse bereitgestellt, und der zugehörige Ansichtscontroller arbeitet direkt mit der konkreten Klasse.

Nun können Sie der Szene das vorgefertigte App-Menü (AppMenu) hinzufügen, um visuelles Feedback zum aktuellen Sitzungszustand zu erhalten. Das App-Menü (AppMenu) zeigt auch den modalen Bereich an, über den Benutzer die Anwendung für die Verbindungsherstellung mit ARR autorisiert.

  1. Navigieren Sie in Assets/RemoteRenderingTutorial/Prefabs/AppMenu zum Prefab AppMenu.

  2. Ziehen Sie das Prefab AppMenu in die Szene.

  3. Wenn ein Dialogfeld für TMP Importer angezeigt wird, befolgen Sie die Anweisungen zum Importieren von TMP Essentials. Schließen Sie anschließend das Dialogfeld „Importer“, da die Beispiele und Extras nicht benötigt werden.

  4. Das App-Menü (AppMenu) ist so konfiguriert, dass automatisch eine Verknüpfung eingerichtet und das modale Fenster bereitgestellt wird, über das der Verbindungsherstellung mit einer Sitzung zugestimmt werden kann. Die zuvor verwendete Umgehung kann somit entfernt werden. Entfernen Sie im GameObject-Element RemoteRenderingCoordinator die zuvor implementierte Autorisierungsumgehung, indem Sie beim Ereignis On Requesting Authorization (Beim Anfordern der Autorisierung) auf die Schaltfläche „-“ klicken.

    Entfernen der Umgehung.

  5. Klicken Sie im Unity-Editor auf Play (Spielen), um den Ansichtscontroller zu testen.

  6. Nachdem das MRTK nun konfiguriert ist, können Sie im Editor mithilfe der Tasten W, A, S und D die Position Ihrer Ansicht ändern und Ihre Blickrichtung ändern, indem Sie bei gedrückter rechter Maustaste die Maus bewegen. Bewegen Sie sich ein wenig durch die Szene, um ein Gefühl für die Steuerung zu bekommen.

  7. Auf dem Gerät können Sie durch Heben Ihrer Handfläche das App-Menü (AppMenu) anzeigen. Im Unity-Editor können Sie dazu die M-TASTE drücken.

  8. Sollte sich das Menü nicht mehr in Ihrem Blickfeld befinden, drücken Sie die M-TASTE, um das Menü anzuzeigen. Das Menü befindet sich zur einfachen Interaktion in der Nähe der Kamera.

  9. Das App-Menü (AppMenu) stellt ein UI-Element für die Autorisierung rechts neben dem AppMenu dar. Ab jetzt sollten Sie dieses UI-Element verwenden, um die App dazu zu autorisieren, Remoterenderingsitzungen zu verwalten.

    Autorisierung über die Benutzeroberfläche

  10. Beenden Sie das Spiel in Unity, um mit dem Tutorial fortzufahren.

Verwalten des Modellzustands

Wir benötigen ein neues Skript namens RemoteRenderedModel. Dieses dient zum Nachverfolgen des Zustands, zum Reagieren auf Ereignisse, zum Auslösen von Ereignissen sowie zur Konfiguration. Von RemoteRenderedModel wird im Wesentlichen der Remotepfad für die Modelldaten in modelPath gespeichert. Es lauscht auf Zustandsänderungen in RemoteRenderingCoordinator, um zu ermitteln, ob das definierte Modell automatisch geladen oder entladen werden soll. Das Spielobjekt, an das RemoteRenderedModel angefügt wird, wird zum lokalen übergeordneten Element für den Remoteinhalt.

Beachten Sie, dass durch das Skript RemoteRenderedModel das Element BaseRemoteRenderedModel aus den Tutorialressourcen implementiert wird. Diese Verbindung ermöglicht die Bindung des Remotemodell-Ansichtscontrollers mit Ihrem Skript.

  1. Erstellen Sie ein neues Skript mit dem Namen RemoteRenderedModel im gleichen Ordner wie RemoteRenderingCoordinator. Ersetzen Sie den gesamten Inhalt durch den folgenden Code:

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License. See LICENSE in the project root for license information.
    
    using Microsoft.Azure.RemoteRendering;
    using Microsoft.Azure.RemoteRendering.Unity;
    using System;
    using UnityEngine;
    using UnityEngine.Events;
    
    public class RemoteRenderedModel : BaseRemoteRenderedModel
    {
        public bool AutomaticallyLoad = true;
    
        private ModelState currentModelState = ModelState.NotReady;
    
        [SerializeField]
        [Tooltip("The friendly name for this model")]
        private string modelDisplayName;
        public override string ModelDisplayName { get => modelDisplayName; set => modelDisplayName = value; }
    
        [SerializeField]
        [Tooltip("The URI for this model")]
        private string modelPath;
        public override string ModelPath
        {
            get => modelPath.Trim();
            set => modelPath = value;
        }
    
        public override ModelState CurrentModelState
        {
            get => currentModelState;
            protected set
            {
                if (currentModelState != value)
                {
                    currentModelState = value;
                    ModelStateChange?.Invoke(value);
                }
            }
        }
    
        public override event Action<ModelState> ModelStateChange;
        public override event Action<float> LoadProgress;
        public override Entity ModelEntity { get; protected set; }
    
        public UnityEvent OnModelNotReady = new UnityEvent();
        public UnityEvent OnModelReady = new UnityEvent();
        public UnityEvent OnStartLoading = new UnityEvent();
        public UnityEvent OnModelLoaded = new UnityEvent();
        public UnityEvent OnModelUnloading = new UnityEvent();
    
        public UnityFloatEvent OnLoadProgress = new UnityFloatEvent();
    
        public void Awake()
        {
            // Hook up the event to the Unity event
            LoadProgress += (progress) => OnLoadProgress?.Invoke(progress);
    
            ModelStateChange += HandleUnityStateEvents;
        }
    
        private void HandleUnityStateEvents(ModelState modelState)
        {
            switch (modelState)
            {
                case ModelState.NotReady:  OnModelNotReady?.Invoke();  break;
                case ModelState.Ready:     OnModelReady?.Invoke();     break;
                case ModelState.Loading:   OnStartLoading?.Invoke();   break;
                case ModelState.Loaded:    OnModelLoaded?.Invoke();    break;
                case ModelState.Unloading: OnModelUnloading?.Invoke(); break;
            }
        }
    
        private void Start()
        {
            //Attach to and initialize current state (in case we're attaching late)
            RemoteRenderingCoordinator.CoordinatorStateChange += Instance_CoordinatorStateChange;
            Instance_CoordinatorStateChange(RemoteRenderingCoordinator.instance.CurrentCoordinatorState);
        }
    
        /// <summary>
        /// Listen for state changes on the coordinator, clean up this model's remote objects if we're no longer connected.
        /// Automatically load if required
        /// </summary>
        private void Instance_CoordinatorStateChange(RemoteRenderingCoordinator.RemoteRenderingState state)
        {
            switch (state)
            {
                case RemoteRenderingCoordinator.RemoteRenderingState.RuntimeConnected:
                    CurrentModelState = ModelState.Ready;
                    if (AutomaticallyLoad)
                        LoadModel();
                    break;
                default:
                    UnloadModel();
                    break;
            }
        }
    
        private void OnDestroy()
        {
            RemoteRenderingCoordinator.CoordinatorStateChange -= Instance_CoordinatorStateChange;
            UnloadModel();
        }
    
        /// <summary>
        /// Asks the coordinator to create a model entity and listens for coordinator state changes
        /// </summary>
        [ContextMenu("Load Model")]
        public override async void LoadModel()
        {
            if (CurrentModelState != ModelState.Ready)
                return; //We're already loaded, currently loading, or not ready to load
    
            CurrentModelState = ModelState.Loading;
    
            ModelEntity = await RemoteRenderingCoordinator.instance?.LoadModel(ModelPath, this.transform, SetLoadingProgress);
    
            if (ModelEntity != null)
                CurrentModelState = ModelState.Loaded;
            else
                CurrentModelState = ModelState.Error;
        }
    
        /// <summary>
        /// Clean up the local model instances
        /// </summary>
        [ContextMenu("Unload Model")]
        public override void UnloadModel()
        {
            CurrentModelState = ModelState.Unloading;
    
            if (ModelEntity != null)
            {
                var modelGameObject = ModelEntity.GetOrCreateGameObject(UnityCreationMode.DoNotCreateUnityComponents);
                Destroy(modelGameObject);
                ModelEntity.Destroy();
                ModelEntity = null;
            }
    
            if (RemoteRenderingCoordinator.instance.CurrentCoordinatorState == RemoteRenderingCoordinator.RemoteRenderingState.RuntimeConnected)
                CurrentModelState = ModelState.Ready;
            else
                CurrentModelState = ModelState.NotReady;
        }
    
        /// <summary>
        /// Update the Unity progress event
        /// </summary>
        /// <param name="progressValue"></param>
        public override void SetLoadingProgress(float progressValue)
        {
            LoadProgress?.Invoke(progressValue);
        }
    }
    

Stark vereinfacht enthält RemoteRenderedModel die zum Laden eines Modells erforderlichen Daten (in diesem Fall den SAS-URI oder den URI builtin:// ) und verfolgt den Remotemodellzustand nach. Beim Laden des Modells wird die Methode LoadModel für RemoteRenderingCoordinator aufgerufen, und die Entität, die das Modell enthält, wird zur Referenz und zum Entladen zurückgegeben.

Laden des Testmodells

Testen wir nun das neue Skript, indem wir noch einmal das Testmodell laden. Für diesen Test benötigen wir ein Game-Objekt, das das Skript enthält und dem Testmodell übergeordnet ist. Außerdem benötigen wir eine virtuelle Stage, die das Modell enthält. Die Stage bleibt relativ zur realen Welt mit einem WorldAnchor fixiert. Wir verwenden eine feste Phase, damit das Modell selbst später noch verschoben werden kann.

  1. Erstellen Sie ein neues leeres Spielobjekt in der Szene, und nennen Sie es ModelStage.

  2. Hinzufügen einer World Anchor-Komponente zu ModelStage

    Hinzufügen der WorldAnchor-Komponente

  3. Erstellen Sie ein neues leeres Spielobjekt als untergeordnetes Element von ModelStage, und nennen Sie es TestModel.

  4. Fügen Sie TestModel das Skript RemoteRenderedModel hinzu.

    Hinzufügen der Komponente „RemoteRenderedModel“

  5. Geben Sie für Model Display Name und Model Path den Wert TestModel bzw. builtin://Engine an.

    Angeben der Modelldetails

  6. Positionieren Sie das Objekt TestModel vor der Kamera an der Position x = 0, y = 0, z = 3.

    Positionieren des Objekts

  7. Vergewissern Sie sich, dass AutomaticallyLoad aktiviert ist.

  8. Klicken Sie im Unity-Editor auf Play (Spielen), um die Anwendung zu testen.

  9. Klicken Sie zur Autorisierung auf die Schaltfläche Verbinden, um der App die Erstellung einer Sitzung zu ermöglichen, sich mit dieser zu verbinden und das Modell automatisch zu laden.

Beobachten Sie die Konsole, während die Anwendung die Zustände durchläuft. Beachten Sie, dass es bei einigen Zuständen etwas dauern kann, bis sie abgeschlossen sind, und es gibt möglicherweise für eine Weile keine Statusupdates. Irgendwann werden die Protokolle des Modells geladenen und kurz danach wird das gerenderte Testmodell in der Szene.

Bewegen und drehen Sie das Game-Objekt TestModel mithilfe der Transformation im Inspektor oder in der Szenenansicht, und beobachten Sie die Transformationen in der Game-Ansicht.

Unity-Protokoll

Bereitstellen von Blob Storage in Azure und Erfassung eines benutzerdefinierten Modells

Nun können wir Ihr eigenes Modell laden. Hierzu müssen Sie Blob Storage in Azure konfigurieren, ein Modell hochladen und konvertieren und dann das Modell mithilfe des Skripts RemoteRenderedModel laden. Sollten Sie noch nicht über ein eigenes Modell zum Laden verfügen, können Sie die Schritte zum Laden eines benutzerdefinierten Modells problemlos überspringen.

Gehen Sie wie unter Schnellstart: Konvertieren eines Modells für das Rendering beschrieben vor. Überspringen Sie für dieses Tutorial den Abschnitt Einfügen eines neuen Modells in die Beispiel-App der Schnellstartanleitung. Fahren Sie fort, wenn Sie über den SAS-URI (Shared Access Signature) Ihres erfassten Modells verfügen.

Laden und Rendern eines benutzerdefinierten Modells

  1. Erstellen Sie in der Szene ein neues leeres Spielobjekt, und nennen Sie es ähnlich wie ihr benutzerdefiniertes Modell.

  2. Fügen Sie dem neu erstellten GameObject-Element das Skript RemoteRenderedModel hinzu.

    Hinzufügen der Komponente „RemoteRenderedModel“

  3. Geben Sie für Model Display Name einen geeigneten Namen für Ihr Modell an.

  4. Geben Sie Model Path mit dem Shared Access Signature (SAS)-URI des Modells an, den Sie im Schritt Bereitstellung von Blob Storage in Azure und benutzerdefinierte Modellerfassung erstellt haben.

  5. Positionieren Sie das Spielobjekt vor der Kamera an der Position x = 0, y = 0, z = 3.

  6. Vergewissern Sie sich, dass AutomaticallyLoad aktiviert ist.

  7. Klicken Sie im Unity-Editor auf Play (Spielen), um die Anwendung zu testen.

    Die Konsole zeigt den aktuellen Sitzungsstatus und auch das Modell beim Laden von Statusmeldungen an, sobald die Sitzung verbunden ist.

  8. Entfernen Sie Ihr benutzerdefiniertes Modellobjekt aus der Szene. Es empfiehlt sich, für dieses Tutorial das Testmodell zu verwenden. In ARR werden zwar mehrere Modelle unterstützt, dieses Tutorial wurde jedoch für die bestmögliche Unterstützung eines einzelnen Remotemodells gestaltet.

Nächste Schritte

Sie können jetzt Ihre eigenen Modelle in Azure Remote Rendering laden und in Ihrer Anwendung anzeigen. Als nächstes zeigen wir Ihnen, wie Sie Ihre Modelle manipulieren.