Oktatóanyag: Interfészek és egyéni modellek

Eben az oktatóanyagban az alábbiakkal fog megismerkedni:

  • Mixed Reality-eszközkészlet hozzáadása a projekthez
  • Modellállapot kezelése
  • Az Azure Blob Storage konfigurálása modellbetöltéshez
  • Modellek feltöltése és feldolgozása rendereléshez

Előfeltételek

Ismerkedés a Mixed Reality eszközkészlettel (MRTK)

A Mixed Reality Eszközkészlet (MRTK) egy platformfüggetlen eszközkészlet a vegyes valósági élmények létrehozásához. Az MRTK 2.8.3-at használjuk az interakciós és vizualizációs funkciókhoz.

Az MRTK importálásának hivatalos útmutatója tartalmaz néhány lépést, amelyeket nem kell tennünk. Csak ez a három lépés szükséges:

  • A "Mixed Reality Toolkit/Mixed Reality Toolkit Foundation" 2.8.3-es verziójának importálása a projektbe a Mixed Reality funkcióeszközön keresztül (MRTK importálása).
  • Futtassa az MRTK konfigurációs varázslóját (AZ MRTK konfigurálása).
  • Adja hozzá az MRTK-t az aktuális jelenethez (Hozzáadás a jelenethez). Az oktatóanyagban javasolt profil helyett használja itt az ARRMixedRealityToolkitConfigurationProfile parancsot.

Az oktatóanyag által használt objektumok importálása

Ebben a fejezetben egy alapszintű modellnézet-vezérlő mintát implementálunk a tárgyalt anyagok nagy részének esetében. A minta modell része az Azure Remote Rendering-specifikus kód és az Azure Remote Renderinghez kapcsolódó állapotkezelés. A minta nézet - és vezérlőrészei MRTK-eszközökkel és néhány egyéni szkripttel vannak implementálva. Ebben az oktatóanyagban a modell az itt implementált nézetvezérlő nélkül is használható. Ezzel az elkülönítéssel könnyedén integrálhatja az oktatóanyagban található kódot a saját alkalmazásába, ahol átveszi a tervezési minta nézetvezérlő részét.

Az MRTK bevezetésével több szkript, előfabs és eszköz is elérhető a projekthez, amelyek mostantól támogatják az interakciókat és a vizuális visszajelzéseket. Ezek az oktatóanyag-objektumok néven említett eszközök egy Unity-eszközcsomagba vannak csomagolva, amely a "\Unity\TutorialAssets\TutorialAssets.unitypackage" Azure Remote Rendering GitHub része.

  1. Klónozza vagy töltse le az Azure Remote Rendering Git-adattárat, ha a letöltéssel kinyeri a zip-fájlt egy ismert helyre.
  2. A Unity-projektben válassza az Eszközök –> Csomag importálása –> Egyéni csomag lehetőséget.
  3. A fájlkezelőben lépjen arra a könyvtárra, ahol klónozta vagy kibontotta az Azure Remote Rendering-adattárat, majd válassza ki a .unitypackageUnity –> TutorialAssets –> TutorialAssets.unitypackage helyen található elemet.
  4. Az Importálás gombra kattintva importálhatja a csomag tartalmát a projektbe.
  5. A Unity Szerkesztőben válassza a Vegyes valóság eszközkészlet –> Segédprogramok –> Az MRTK Standard Shader frissítése egyszerűsített renderelési folyamathoz lehetőséget a felső menüsávon, és kövesse az utasításokat a shader frissítéséhez.

Miután az MRTK és a Tutorial Assets beállítása megtörtént, ellenőrizze, hogy a megfelelő profil van-e kiválasztva.

  1. Válassza a MixedRealityToolkit GameObject elemet a jelenethierarchiában.
  2. Az Inspector MixedRealityToolkit összetevőjében állítsa át a konfigurációs profilt az ARRMixedRealityToolkitConfigurationProfile értékre.
  3. A módosítások mentéséhez nyomja le a Ctrl+S billentyűkombinációt.

Ez a lépés elsősorban az MRTK-t konfigurálja az alapértelmezett HoloLens 2 profilokkal. A megadott profilok az alábbi módokon vannak előre konfigurálva:

  • Kapcsolja ki a profilkészítőt (nyomja le a 9 billentyűt, hogy be- vagy kikapcsolja, vagy mondja ki a "Profiler megjelenítése/elrejtése" parancsot az eszközön).
  • Kapcsolja ki a szem tekintetének kurzorát.
  • Engedélyezze a Unity-egérkattintásokat, így az MRTK felhasználói felület elemeire a szimulált kéz helyett az egérrel kattinthat.

Az Alkalmazás menü hozzáadása

Az oktatóanyag legtöbb nézetvezérlője absztrakt alaposztályokon működik a konkrét osztályok helyett. Ez a minta nagyobb rugalmasságot biztosít, és lehetővé teszi számunkra a nézetvezérlők biztosítását, miközben továbbra is segítünk az Azure Remote Rendering-kód megismerésében. Az egyszerűség kedvéért a RemoteRenderingCoordinator osztály nem rendelkezik absztrakt osztálysal, és a nézetvezérlő közvetlenül a konkrét osztályon működik.

Most már hozzáadhatja az előregyártott AppMenu-t a jelenethez, hogy vizuálisan visszajelzést adjon az aktuális munkamenet állapotáról. Az AppMenu azt a modális panelt is megjeleníti, amelyet a felhasználó az alkalmazás ARR-hez való csatlakozásának engedélyezéséhez használ.

  1. Keresse meg az AppMenu előtagot az Assets/RemoteRenderingTutorial/Prefabs/AppMenu fájlban

  2. Húzza az AppMenu előképet a jelenetbe.

  3. Ha megjelenik a TMP Importer párbeszédpanelje, kövesse az utasításokat a TMP Essentials importálásához. Ezután zárja be az importáló párbeszédpanelt, mivel a példákra és az extrákra nincs szükség.

  4. Az AppMenu úgy van konfigurálva, hogy automatikusan összekapcsolja a munkamenetet, és megadja a munkamenethez való csatlakozás engedélyezéséhez szükséges modális beállítást, hogy eltávolíthassuk a korábban elhelyezett megkerülést. A RemoteRenderingCoordinator GameObject elemen távolítsa el a korábban implementált engedélyezés megkerülését a "-" gomb megnyomásával az Engedélyezéskor eseményen.

    Megkerülés eltávolítása.

  5. A nézetvezérlő teszteléséhez nyomja le a Lejátszás gombot a Unity Szerkesztőben.

  6. A Szerkesztőben most, hogy az MRTK konfigurálva lett, a WASD billentyűkkel módosíthatja a nézet pozícióját, és a jobb egérgombot lenyomva tartva módosíthatja a nézet irányát. Próbálja ki a "vezetés" körül a jelenet egy kicsit, hogy egy kicsit érezni a vezérlők.

  7. Az eszközön felemelheti a tenyerét az AppMenu megidézéséhez, a Unity Szerkesztőben használja az "M" gyorsbillentyűt.

  8. Ha nem látta a menüt, nyomja le az "M" billentyűt a menü megidézéséhez. A menü a kamera közelében található az egyszerű interakció érdekében.

  9. Az AppMenu egy felhasználói felületi elemet jelenít meg az AppMenu jobb oldalán történő engedélyezéshez. Mostantól ezt a felhasználói felületi elemet kell használnia ahhoz, hogy engedélyezze az alkalmazást a távoli renderelési munkamenetek kezeléséhez.

    Felhasználói felület engedélyezése

  10. Az oktatóanyag folytatásához állítsa le a Unity játékát.

Modellállapot kezelése

Szükségünk van egy RemoteRenderedModel nevű új szkriptre, amely nyomon követi az állapotot, válaszol az eseményekre, aktiválja az eseményeket és a konfigurációt. A RemoteRenderedModel lényegében a modelladatok távoli elérési útját tárolja a fájlban modelPath. Figyeli a RemoteRenderingCoordinator állapotváltozásait, hogy lássa, automatikusan be kell-e töltenie vagy ki kell-e ürítenie az általa definiált modellt. A RemoteRenderedModel objektumot tartalmazó GameObject a távoli tartalom helyi szülője.

Figyelje meg, hogy a RemoteRenderedModel szkript implementálja a BaseRemoteRenderedModel parancsprogramot, amely a Tutorial Assets része. Ez a kapcsolat lehetővé teszi, hogy a távoli modellnézet-vezérlő kösse össze a szkriptet.

  1. Hozzon létre egy RemoteRenderedModel nevű új szkriptet a RemoteRenderingCoordinator mappában. Cserélje le a teljes tartalmat a következő kódra:

    // 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);
        }
    }
    

A remoteRenderedModel a modell betöltéséhez szükséges adatokat (ebben az esetben az SAS-t vagy az builtin:// URI-t) tárolja, és nyomon követi a távoli modell állapotát. Amikor ideje betölteni a modellt, a rendszer meghívja a LoadModel metódust a RemoteRenderingCoordinatoron, és a modellt tartalmazó entitást adja vissza referenciaként és eltávolításra.

A tesztmodell betöltése

Teszteljük az új szkriptet a tesztmodell újbóli betöltésével. Ehhez a teszthez egy Game Object objektumra van szükségünk, amely tartalmazza a szkriptet, és szülője lesz a tesztmodellnek, valamint egy virtuális fázisra, amely tartalmazza a modellt. A színpad a való világhoz képest állandó marad a WorldAnchor használatával. Rögzített fázist használunk, hogy maga a modell később is áthelyezhető legyen.

  1. Hozzon létre egy új üres Játékobjektumot a jelenetben, és adja neki a ModelStage nevet.

  2. World Anchor összetevő hozzáadása a ModelStage-hez

    WorldAnchor-összetevő hozzáadása

  3. Hozzon létre egy új üres Játékobjektumot a ModelStage gyermekeként, és nevezze el TestModel néven.

  4. Adja hozzá a RemoteRenderedModel szkriptet a TestModelhez.

    RemoteRenderedModel összetevő hozzáadása

  5. Töltse ki a és a Model Display Name értéket a Model Path "TestModel" és a "builtin://Engine" kifejezéssel.

    Modell részleteinek megadása

  6. Helyezze a TestModel objektumot a kamera elé x = 0, y = 0, z = 3 pozícióban.

    Objektum elhelyezése

  7. Győződjön meg arról, hogy az Automatikus betöltés be van kapcsolva.

  8. Az alkalmazás teszteléséhez nyomja le a Play billentyűt a Unity Szerkesztőben.

  9. Engedélyezze az engedélyezést a Csatlakozás gombra kattintva, hogy az alkalmazás létrehozhat egy munkamenetet, csatlakozhat hozzá, és automatikusan betöltheti a modellt.

Figyelje meg a konzolt, ahogy az alkalmazás végighalad az állapotán. Ne feledje, hogy egyes állapotok végrehajtása eltarthat egy ideig, és előfordulhat, hogy egy ideig nem lesznek folyamatban lévő frissítések. Végül a modellbetöltés naplói jelennek meg, majd röviddel a renderelt tesztmodell után a jelenetben.

Próbálja meg áthelyezni és elforgatni a TestModel GameObject objektumot az Inspector átalakításával, vagy a Jelenet nézetben, és figyelje meg az átalakításokat a Játék nézetben.

Unity-napló

Blob Storage kiépítése az Azure-ban és egyéni modellbetöltés

Most megpróbálhatjuk betölteni a saját modelljét. Ehhez konfigurálnia kell a Blob Storage-t az Azure-ban, fel kell töltenie és konvertálnia kell egy modellt, majd be kell töltenie a modellt a RemoteRenderedModel szkripttel. Az egyéni modell betöltési lépéseit nyugodtan kihagyhatja, ha jelenleg nincs saját betöltési modellje.

Kövesse a Gyorsútmutató: Modell konvertálása rendereléshez című szakasz lépéseit. Az oktatóanyaghoz hagyja ki az Új modell beszúrása rövid útmutató mintaalkalmazásba szakaszt. Miután megkapta a betöltött modell közös hozzáférésű jogosultságkódjának (SAS) URI-ját, folytassa.

Egyéni modell betöltése és renderelése

  1. Hozzon létre egy új üres GameObjectet a jelenetben, és nevezze el az egyéni modellhez hasonlóan.

  2. Adja hozzá a RemoteRenderedModel szkriptet az újonnan létrehozott GameObjecthez.

    RemoteRenderedModel összetevő hozzáadása

  3. Adja meg a Model Display Name modell megfelelő nevét.

  4. Töltse ki a Model Path modellt az Azure-beli Blob Storage kiépítése és az egyéni modellbetöltési lépésben létrehozott közös hozzáférésű jogosultságkód (SAS) URI-jával.

  5. Helyezze a GameObjectet a kamera elé x = 0, y = 0, z = 3 pozícióban.

  6. Győződjön meg arról, hogy az Automatikus betöltés be van kapcsolva.

  7. Az alkalmazás teszteléséhez nyomja le a Play billentyűt a Unity-szerkesztőben.

    A konzol megjeleníti a munkamenet aktuális állapotát, valamint a folyamatüzeneteket betöltő modellt is, miután a munkamenet csatlakozik.

  8. Távolítsa el az egyéni modellobjektumot a jelenetből. Ennek az oktatóanyagnak a legjobb élménye a tesztmodell. Bár az ARR-ben több modell is támogatott, ezt az oktatóanyagot úgy írtuk meg, hogy egyszerre egyetlen távoli modellt támogatjon a legjobban.

Következő lépések

Most már betöltheti saját modelljeit az Azure Remote Renderingbe, és megtekintheti őket az alkalmazásban! Ezután végigvezetjük a modellek manipulálásán.