Samouczek: interfejsy i modele niestandardowe

Ten samouczek zawiera informacje na temat wykonywania następujących czynności:

  • Dodawanie zestawu narzędzi Mixed Reality do projektu
  • Zarządzanie stanem modelu
  • Konfigurowanie Azure Blob Storage na potrzeby pozyskiwania modelu
  • Przekazywanie i przetwarzanie modeli renderowania

Wymagania wstępne

Wprowadzenie do zestawu narzędzi Mixed Reality Toolkit (MRTK)

Zestaw narzędzi Mixed Reality Toolkit (MRTK) to międzyplatformowy zestaw narzędzi do tworzenia środowisk rzeczywistości mieszanej. Używamy zestawu MRTK 2.8.3 do interakcji i funkcji wizualizacji.

Oficjalny przewodnik dotyczący importowania zestawu narzędzi MRTK zawiera kilka kroków, których nie trzeba robić. Niezbędne są tylko te trzy kroki:

Importowanie zasobów używanych przez ten samouczek

Począwszy od tego rozdziału, zaimplementujemy podstawowy wzorzec kontrolera widoku modelu dla dużej części pokrytego materiału. Część modelu wzorca to kod specyficzny dla platformy Azure Remote Rendering oraz zarządzanie stanem związane z usługą Azure Remote Rendering. Części widoku i kontrolera wzorca są implementowane przy użyciu zasobów zestawu narzędzi MRTK i niektórych skryptów niestandardowych. W tym samouczku można użyć modelu bez zaimplementowanego tutaj kontrolera widoku . Ta separacja umożliwia łatwe zintegrowanie kodu znalezionego w tym samouczku z własną aplikacją, w której przejmuje część wzorca projektowania kontrolera widoku .

Wraz z wprowadzeniem zestawu narzędzi MRTK istnieje wiele skryptów, prefabów i zasobów, które można teraz dodać do projektu w celu obsługi interakcji i opinii wizualnych. Te zasoby nazywane zasobami samouczka są dołączane do pakietu zasobów aparatu Unity, który znajduje się w usłudze Azure Remote Rendering GitHub w folderze "\Unity\TutorialAssets\TutorialAssets.unitypackage".

  1. Sklonuj lub pobierz repozytorium git azure Remote Rendering, jeśli pobierzesz plik zip do znanej lokalizacji.
  2. W projekcie aparatu Unity wybierz pozycję Assets —> Import Package — Custom Package (Zaimportuj pakiet —> pakiet niestandardowy).
  3. W Eksploratorze plików przejdź do katalogu, w którym sklonujesz lub rozpakujesz repozytorium usługi Azure Remote Rendering, a następnie wybierz .unitypackage plik znaleziony w obszarze Unity —> TutorialAssets — TutorialAssets -> TutorialAssets.unitypackage
  4. Wybierz przycisk Importuj , aby zaimportować zawartość pakietu do projektu.
  5. W edytorze aparatu Unity wybierz pozycję Mixed Reality Toolkit —> Utilities —> Upgrade MRTK Standard Shader for Lightweight Render Pipeline (Uaktualnianie cieniowania standardowego zestawu narzędzi MRTK dla uproszczonego potoku renderowania) na górnym pasku menu i postępuj zgodnie z monitami o uaktualnienie cieniowania.

Po skonfigurowaniu zestawu narzędzi MRTK i zasobów samouczka sprawdź dwukrotnie, czy wybrano prawidłowy profil.

  1. Wybierz obiekt MixedRealityToolkit GameObject w hierarchii sceny.
  2. W inspektorze w obszarze składnika MixedRealityToolkit przełącz profil konfiguracji na ARRMixedRealityToolkitConfigurationProfile.
  3. Naciśnij klawisze Ctrl+S , aby zapisać zmiany.

Ten krok służy przede wszystkim do konfigurowania zestawu narzędzi MRTK z domyślnymi profilami HoloLens 2. Podane profile są wstępnie skonfigurowane w następujący sposób:

  • Wyłącz profilera (naciśnij klawisz 9, aby go włączyć/wyłączyć lub powiedzieć "Pokaż/Ukryj profilera" na urządzeniu).
  • Wyłącz kursor wzroku.
  • Włącz kliknięcia myszy aparatu Unity, aby można było kliknąć elementy interfejsu użytkownika zestawu narzędzi MRTK za pomocą myszy zamiast symulowanej ręki.

Dodaj menu Aplikacji

Większość kontrolerów widoków w tym samouczku działa względem abstrakcyjnych klas bazowych zamiast klas betonowych. Ten wzorzec zapewnia większą elastyczność i umożliwia nam udostępnianie kontrolerów widoków, a jednocześnie ułatwia naukę kodu usługi Azure Remote Rendering. Dla uproszczenia klasa RemoteRenderingCoordinator nie ma udostępnionej klasy abstrakcyjnej, a jej kontroler widoku działa bezpośrednio względem betonowej klasy.

Teraz możesz dodać prefab AppMenu do sceny, aby uzyskać wizualną opinię o bieżącym stanie sesji. AplikacjaMenu przedstawia również modalny panel używany przez użytkownika do autoryzowania aplikacji w celu nawiązania połączenia z usługą ARR.

  1. Znajdź prefab appMenu w obszarze Assets/RemoteRenderingTutorial/Prefabs/AppMenu

  2. Przeciągnij prefab aplikacji AppMenu do sceny.

  3. Jeśli zostanie wyświetlone okno dialogowe importera TMP, postępuj zgodnie z monitami, aby zaimportować podstawowe elementy TMP. Następnie zamknij okno dialogowe importera, ponieważ przykłady i dodatki nie są potrzebne.

  4. Aplikacja AppMenu jest skonfigurowana do automatycznego podłączania i zapewnia modalne wyrażenie zgody na nawiązanie połączenia z sesją, dzięki czemu możemy usunąć obejście umieszczone wcześniej. W obiekcie RemoteRenderingCoordinator GameObject usuń obejście dla autoryzacji wdrożonej wcześniej, naciskając przycisk "-" na zdarzeniu On Requesting Authorization (Żądanie autoryzacji ).

    Usuń obejście.

  5. Przetestuj kontroler widoku, naciskając klawisz Play w edytorze aparatu Unity.

  6. W edytorze po skonfigurowaniu zestawu NARZĘDZI MRTK możesz użyć klawiszy WASD, aby zmienić położenie widoku i przytrzymując prawy przycisk myszy i przesuwając mysz, aby zmienić kierunek widoku. Spróbuj "jazdy" wokół sceny nieco, aby poczuć się dla kontrolek.

  7. Na urządzeniu możesz podnieść rękę, aby wywołać aplikację AppMenu, w edytorze aparatu Unity, użyć klawisza "M".

  8. Jeśli utracisz widok menu, naciśnij klawisz "M", aby wywołać menu. Menu znajduje się w pobliżu aparatu w celu łatwej interakcji.

  9. Element AppMenu przedstawia element interfejsu użytkownika na potrzeby autoryzacji po prawej stronie aplikacji AppMenu. Od teraz należy użyć tego elementu interfejsu użytkownika, aby autoryzować aplikację do zarządzania sesjami renderowania zdalnego.

    Autoryzacja interfejsu użytkownika

  10. Zatrzymaj odtwarzanie aparatu Unity, aby kontynuować pracę z samouczkiem.

Zarządzanie stanem modelu

Potrzebujemy nowego skryptu o nazwie RemoteRenderedModel , który służy do śledzenia stanu, reagowania na zdarzenia, wyzwalania zdarzeń i konfiguracji. Zasadniczo model RemoteRenderedModel przechowuje ścieżkę zdalną dla danych modelu w programie modelPath. Nasłuchuje on zmian stanu w RemoteRenderingCoordinator , aby sprawdzić, czy powinien automatycznie załadować lub zwolnić model, który definiuje. Obiekt GameObject, który ma element RemoteRenderedModel dołączony do niego, jest lokalnym elementem nadrzędnym dla zawartości zdalnej.

Zwróć uwagę, że skrypt RemoteRenderedModel implementuje model BaseRemoteRenderedModel uwzględniony w sekcji Zasoby samouczka. To połączenie umożliwia kontrolerowi widoku modelu zdalnego powiązanie ze skryptem.

  1. Utwórz nowy skrypt o nazwie RemoteRenderedModel w tym samym folderze co RemoteRenderingCoordinator. Zastąp całą zawartość następującym kodem:

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

W najbardziej podstawowych kategoriach RemoteRenderedModel przechowuje dane potrzebne do załadowania modelu (w tym przypadku sygnatury dostępu współdzielonego lub identyfikatora URI builtin:// ) i śledzi stan modelu zdalnego. Gdy nadszedł czas na załadowanie modelu, LoadModel metoda jest wywoływana w remoteRenderingCoordinator, a jednostka zawierająca model jest zwracana do odwołania i zwalniania.

Ładowanie modelu testowego

Przetestujmy nowy skrypt, ładując ponownie model testowy. Na potrzeby tego testu potrzebujemy obiektu gry, aby zawierał skrypt i być elementem nadrzędnym modelu testowego, a także potrzebujemy wirtualnego etapu zawierającego model. Scena pozostaje stała względem świata rzeczywistego przy użyciu WorldAnchor. Używamy stałego etapu, aby sam model mógł być nadal przenoszony później.

  1. Utwórz nowy pusty obiekt gry w scenie i nadaj mu nazwę ModelStage.

  2. Dodawanie składnika zakotwiczenia świata do elementu ModelStage

    Dodawanie składnika WorldAnchor

  3. Utwórz nowy pusty obiekt gry jako element podrzędny ModeluStage i nadaj mu nazwę TestModel.

  4. Dodaj skrypt RemoteRenderedModel do modelu TestModel.

    Dodawanie składnika RemoteRenderedModel

  5. Model Display Name Wypełnij pola i Model Path odpowiednio "TestModel" i "builtin://Engine".

    Określanie szczegółów modelu

  6. Umieść obiekt TestModel przed kamerą, na pozycji x = 0, y = 0, z = 3.

    Położenie obiektu

  7. Upewnij się, że opcja Automatycznie ładuj jest włączona.

  8. Naciśnij klawisz Play w edytorze aparatu Unity, aby przetestować aplikację.

  9. Udziel autoryzacji, klikając przycisk Połącz , aby umożliwić aplikacji tworzenie sesji, łączenie się z nim i automatyczne ładowanie modelu.

Obserwuj konsolę, gdy aplikacja przechodzi przez jej stany. Należy pamiętać, że niektóre stany mogą zająć trochę czasu i na pewien czas nie ma żadnych aktualizacji postępu. W końcu zobaczysz dzienniki z ładowania modelu, a następnie wkrótce po renderowanym modelu testowym w scenie.

Spróbuj przenieść i obracać obiekt TestModel GameObject za pośrednictwem elementu Transform w inspektorze lub w widoku Scena i obserwować przekształcenia w widoku Gry.

Dziennik aparatu Unity

Aprowizuj usługę Blob Storage na platformie Azure i pozyskiwanie modelu niestandardowego

Teraz możemy spróbować załadować własny model. W tym celu należy skonfigurować usługę Blob Storage na platformie Azure, przekazać i przekonwertować model, a następnie załadować model przy użyciu skryptu RemoteRenderedModel . Kroki ładowania modelu niestandardowego można bezpiecznie pominąć, jeśli nie masz własnego modelu do załadowania w tej chwili.

Wykonaj kroki określone w przewodniku Szybki start: konwertowanie modelu na potrzeby renderowania. Pomiń sekcję Wstawianie nowego modelu do sekcji Przykładowa aplikacja szybkiego startu dla tego samouczka. Po uzyskaniu identyfikatora URI sygnatury dostępu współdzielonego (SAS) modelu pozyskanego kontynuuj.

Ładowanie i renderowanie modelu niestandardowego

  1. Utwórz nowy pusty obiekt GameObject w scenie i nadaj mu nazwę podobną do modelu niestandardowego.

  2. Dodaj skrypt RemoteRenderedModel do nowo utworzonego obiektu GameObject.

    Dodawanie składnika RemoteRenderedModel

  3. Model Display Name Wprowadź odpowiednią nazwę modelu.

  4. Model Path Wypełnij identyfikator URI sygnatury dostępu współdzielonego (SAS) modelu utworzony w kroku Aprowizowania usługi Blob Storage na platformie Azure i pozyskiwania modelu niestandardowego.

  5. Umieść obiekt GameObject przed kamerą, na pozycji x = 0, y = 0, z = 3.

  6. Upewnij się, że opcja Automatycznie ładuj jest włączona.

  7. Naciśnij klawisz Play w edytorze aparatu Unity, aby przetestować aplikację.

    Konsola pokazuje bieżący stan sesji, a także komunikaty o postępie ładowania modelu po nawiązaniu połączenia z sesją.

  8. Usuń obiekt modelu niestandardowego ze sceny. Najlepszym rozwiązaniem tego samouczka jest model testowy. Chociaż wiele modeli jest obsługiwanych w usłudze ARR, ten samouczek został napisany w celu zapewnienia najlepszej obsługi pojedynczego modelu zdalnego naraz.

Następne kroki

Teraz możesz załadować własne modele do usługi Azure Remote Rendering i wyświetlić je w aplikacji! Następnie przeprowadzimy Cię przez manipulowanie modelami.