Sdílet prostřednictvím


Kurz: Zobrazení vzdáleného vykresleného modelu

V tomto kurzu se naučíte:

  • Zřízení instance služby Azure Remote Rendering (ARR)
  • Vytvoření a zastavení relace vykreslování
  • Opakované použití existující relace vykreslování
  • Připojení a odpojení od relací
  • Načtení modelů do relace vykreslování

Požadavky

Pro účely tohoto kurzu potřebujete:

Zřízení instance služby Azure Remote Rendering (ARR)

Pokud chcete získat přístup ke službě Azure Remote Rendering, musíte nejprve vytvořit účet.

Vytvoření nového projektu Unity

Tip

Úložiště ukázek ARR obsahuje projekt se všemi dokončenými kurzy. Můžete ho použít jako referenci. Podívejte se do Unity\Tutorial-Complete pro kompletní projekt Unity.

V Centru Unity vytvořte nový projekt. V tomto příkladu předpokládáme, že se projekt vytváří ve složce s názvem RemoteRendering.

Snímek obrazovky Centra Unity s dialogovým oknem Vytvořit nový projekt Unity Je vybrán panel 3D.

Zahrnutí balíčků Azure Remote Rendering a OpenXR

Postupujte podle pokynů k přidání balíčků Azure Remote Rendering a OpenXR do projektu Unity.

Poznámka:

Pokud Unity po importu balíčku OpenXR zobrazí dialogové okno upozornění s dotazem, jestli chcete povolit back-endy nativní platformy pro nový vstupní systém, klikněte prozatím na tlačítko Ne . Povolíte ho v pozdějším kroku.

Konfigurace kamery

  1. Vyberte uzel Hlavní Kamera.

  2. Otevřete místní nabídku tak, že kliknete pravým tlačítkem myši na komponentu Transformovat a vyberete možnost Obnovit :

    Snímek obrazovky s inspektorem Unity pro komponentu Transformace Otevře se místní nabídka a vybere se možnost Obnovit.

  3. Nastavení jasných příznaků na plnou barvu

  4. Nastavení pozadí na černou (#000000) s plně průhledným (0) alfa (A)

    Snímek obrazovky s dialogovým oknem Kolo barvy Unity Barva je nastavená na 0 pro všechny součásti R G B A.

  5. Nastavte roviny výřezu na hodnotu Near = 0,1 a Far = 20. Toto nastavení znamená vykreslování geometrie klipů, které jsou blíže než 10 cm nebo delší než 20 metrů.

    Snímek obrazovky s inspektorem Unity pro komponentu Kamera

Úprava nastavení projektu

  1. Otevřít Nastavení upravit > projekt...

  2. Výběr kvality v nabídce levého seznamu

    1. Změňte výchozí úroveň kvality všech platforem na Nízkou. Toto nastavení umožňuje efektivnější vykreslování místního obsahu a nemá vliv na kvalitu vzdáleného vykresleného obsahu.

      Snímek obrazovky s dialogovým Nastavení projektu Unity Položka Kvalita je vybrána v seznamu vlevo. Na pravé straně se otevře místní nabídka výchozí úrovně kvality. Je vybrána nízká položka.

    Poznámka:

    V oboru tohoto kurzu se budeme držet integrovaného kanálu vykreslování Unity. Pokud chcete použít kanál univerzálního vykreslení, další kroky nastavení najdete v kanálech Vykreslování Unity.

  3. V nabídce levého seznamu vyberte Správu modulů plug-in XR.

    1. Klikněte na tlačítko Nainstalovat správu modulů plug-in XR.
    2. Vyberte kartu nastavení Univerzální platforma Windows znázorněnou jako ikona Windows.
    3. Zaškrtněte políčko Otevřít XR v části Poskytovatelé modulů plug-in.
    4. Pokud se otevře dialogové okno s žádostí o povolení back-endů nativní platformy pro nový vstupní systém, vyberte Ne.

    Snímek obrazovky s dialogovým Nastavení projektu Unity Položka Správy modulů plug-in XR je vybrána v seznamu vlevo. Na pravé straně je zvýrazněná karta s logem windows. Zobrazí se také zaškrtávací políčko Otevřít XR pod ním.

    Poznámka:

    Pokud je skupina funkcí Microsoft HoloLens zakázaná, chybí v projektu modul plug-in Windows Mixed Reality OpenXR. Postupujte podle pokynů k přidání balíčků Azure Remote Rendering a OpenXR, které chcete nainstalovat.

  4. V nabídce levého seznamu vyberte OpenXR .

    1. Nastavení režimu odeslání hloubky na hloubku 16 bitů
    2. Přidejte profil interakce rukou microsoftu do profilů interakce.
    3. Povolte tyto funkce OpenXR:
      • Azure Remote Rendering
      • Sledování rukou
      • Funkce hybridní reality
      • Model ovladače pohybu

    Snímek obrazovky s dialogovým Nastavení projektu Unity V seznamu vlevo je vybrána podsložka Otevřít XR. Zvýraznění na pravé straně se umístí do režimu odeslání hloubky, profilů interakce a nastavení funkce Otevřít XR.

    Poznámka:

    Pokud v projektu nevidíte požadované funkce OpenXR uvedené v modulu plug-in Windows Mixed Reality OpenXR. Postupujte podle pokynů k přidání balíčků Azure Remote Rendering a OpenXR, které chcete nainstalovat.

  5. Výběr přehrávače v nabídce levého seznamu

    1. Vyberte kartu nastavení Univerzální platforma Windows znázorněnou jako ikona Windows.
    2. Rozbalit další Nastavení
    3. V části Vykreslování změňte barevný prostor na lineární a restartujte Unity, když vás požádá.
    4. V části Konfigurace změňte aktivní zpracování vstupu na Obě a restartujte Unity, když vás požádá. Snímek obrazovky s dialogovým Nastavení projektu Unity Položka Player je vybrána v seznamu vlevo. Zvýraznění na pravé straně se umístí na kartu s logem Windows, nastavením Barevné místo a nastavením Aktivní zpracování vstupu.
    5. Rozbalit Nastavení publikování
    6. Posuňte se dolů na Možnosti a vyberte:
      • InternetClient
      • InternetClientServer
      • SpatialPerception
      • PrivateNetworkClientServer (volitelné). Tuto možnost vyberte, pokud chcete ke svému zařízení připojit vzdálený ladicí program Unity.
    7. V části Podporované rodiny zařízení povolte Holographic and DesktopSnímek obrazovky s dialogovým Nastavení projektu Unity Položka Player je vybrána v seznamu vlevo. Zvýraznění na pravé straně se umístí na možnosti a nastavení Podporované rodiny zařízení.
  6. Zavření nebo ukotvení panelu Nastavení Projectu

  7. Otevření Nastavení sestavení souborů>

    1. Výběr Univerzální platforma Windows
    2. Nakonfigurujte nastavení tak, aby odpovídala těm, které najdete níže.
    3. Stiskněte tlačítko Přepnout platformu.
      Snímek obrazovky s dialogovým oknem Unity Build Nastavení Položka Univerzální platforma Windows je vybrána v seznamu vlevo. Zvýraznění na pravé straně se umístí do rozevíracích polí nastavení a na tlačítko Přepnout platformu.
  8. Po změně platforem Unity zavřete panel sestavení.

Ověření nastavení projektu

Provedením následujících kroků ověřte správnost nastavení projektu.

  1. V nabídce RemoteRendering na panelu nástrojů editoru Unity zvolte položku ValidateProject.

  2. Zkontrolujte chyby v okně Validatoru projektu a v případě potřeby opravte nastavení projektu.

    Snímek obrazovky s dialogovým oknem Validátor projektu Unity V dialogovém okně se zobrazí seznam požadovaných, doporučených a vývojových pravidel, která jsou všechna úspěšná kontrola.

Poznámka:

Pokud ve svém projektu používáte MRTK a povolíte subsystém kamery, MRTK přepíše ruční změny, které použijete na kameru. To zahrnuje opravy z nástroje ValidateProject.

Vytvoření skriptu pro koordinaci připojení a stavu služby Azure Remote Rendering

Existují čtyři základní fáze k zobrazení vzdáleně vykreslených modelů, které jsou popsané v vývojovém diagramu níže. Každá fáze musí být provedena v pořadí. Dalším krokem je vytvoření skriptu, který spravuje stav aplikace a prochází každou požadovanou fázi.

Diagram čtyř fází potřebných k načtení modelu

  1. V podokně Projekt vytvořte v části Prostředky novou složku s názvem RemoteRenderingCore. Pak uvnitř RemoteRenderingCore vytvořte další složku s názvem Scripts.

  2. Vytvořte nový skript jazyka C# s názvem RemoteRenderingCoordinator. Projekt by měl vypadat takto:

    Snímek obrazovky s hierarchií projektu Unity obsahující nový skript

    Tento koordinační skript sleduje a spravuje stav vzdáleného vykreslování. Všimněte si, že některé z těchto kódů se používají k udržování stavu, zpřístupnění funkcí jiným komponentám, aktivaci událostí a ukládání dat specifických pro aplikaci, která přímo nesouvisí se službou Azure Remote Rendering. Jako výchozí bod použijte následující kód a budeme řešit konkrétní kód Azure Remote Rendering a implementovat ho později v tomto kurzu.

  3. Otevřete RemoteRenderingCoordinator v editoru kódu a nahraďte celý jeho obsah následujícím kódem:

// 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 System.Linq;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;

#if UNITY_WSA
using UnityEngine.XR.WSA;
#endif

/// <summary>
/// Remote Rendering Coordinator is the controller for all Remote Rendering operations.
/// </summary>

// Require the GameObject with a RemoteRenderingCoordinator to also have the ARRServiceUnity component
[RequireComponent(typeof(ARRServiceUnity))]
public class RemoteRenderingCoordinator : MonoBehaviour
{
    public enum RemoteRenderingState
    {
        NotSet,
        NotInitialized,
        NotAuthorized,
        NoSession,
        ConnectingToExistingRemoteSession,
        ConnectingToNewRemoteSession,
        RemoteSessionReady,
        ConnectingToRuntime,
        RuntimeConnected
    }

    public static RemoteRenderingCoordinator instance;

    // Account
    // RemoteRenderingDomain must be '<region>.mixedreality.azure.com' - if no '<region>' is specified, connections will fail
    // For most people '<region>' is either 'westus2' or 'westeurope'
    [SerializeField]
    private string remoteRenderingDomain = "westus2.mixedreality.azure.com";
    public string RemoteRenderingDomain
    {
        get => remoteRenderingDomain.Trim();
        set => remoteRenderingDomain = value;
    }

    [Header("Development Account Credentials")]
    [SerializeField]
    private string accountDomain = "<enter your account domain here>";
    public string AccountDomain
    {
        get => accountDomain.Trim();
        set => accountDomain = value;
    }

    [SerializeField]
    private string accountId = "<enter your account id here>";
    public string AccountId {
        get => accountId.Trim();
        set => accountId = value;
    }

    [SerializeField]
    private string accountKey = "<enter your account key here>";
    public string AccountKey {
        get => accountKey.Trim();
        set => accountKey = value;
    }

    // These settings are important. All three should be set as low as possible, while maintaining a good user experience
    // See the documentation around session management and the technical differences in session VM size
    [Header("New Session Defaults")]

    public RenderingSessionVmSize renderingSessionVmSize = RenderingSessionVmSize.Standard;
    public uint maxLeaseHours = 0;
    public uint maxLeaseMinutes = 20;

    [Header("Other Configuration")]

    [Tooltip("If you have a known active SessionID, you can fill it in here before connecting")]
    [SerializeField]
    private string sessionIDOverride;
    public string SessionIDOverride {
        get => sessionIDOverride.Trim();
        set => sessionIDOverride = value;
    }

    // When Automatic Mode is true, the coordinator will attempt to automatically proceed through the process of connecting and loading a model
    public bool automaticMode = true;

    public event Action RequestingAuthorization;
    public UnityEvent OnRequestingAuthorization = new UnityEvent();

    public event Action AuthorizedChanged;
    public UnityEvent OnAuthorizationChanged = new UnityEvent();
    private bool authorized;
    public bool Authorized
    {
        get => authorized;
        set
        {
            if (value == true) //This is a one-way value, once we're authorized it lasts until the app is shutdown.
            {
                authorized = value;
                AuthorizedChanged?.Invoke();
            }
        }
    }

    public delegate Task<SessionConfiguration> AccountInfoGetter();

    public static AccountInfoGetter ARRCredentialGetter
    {
        private get;
        set;
    }

    private RemoteRenderingState currentCoordinatorState = RemoteRenderingState.NotSet;
    public RemoteRenderingState CurrentCoordinatorState
    {
        get => currentCoordinatorState;
        private set
        {
            if (currentCoordinatorState != value)
            {
                currentCoordinatorState = value;
                Debug.LogFormat(LogType.Log, LogOption.NoStacktrace, null, "{0}", $"State changed to: {currentCoordinatorState}");
                CoordinatorStateChange?.Invoke(currentCoordinatorState);
            }
        }
    }

    public static event Action<RemoteRenderingState> CoordinatorStateChange;

    public static RenderingSession CurrentSession => instance?.ARRSessionService?.CurrentActiveSession;

    private ARRServiceUnity arrSessionService;

    private ARRServiceUnity ARRSessionService
    {
        get
        {
            if (arrSessionService == null)
                arrSessionService = GetComponent<ARRServiceUnity>();
            return arrSessionService;
        }
    }

    private async Task<SessionConfiguration> GetDevelopmentCredentials()
    {
        Debug.LogWarning("Using development credentials! Not recommended for production.");
        return await Task.FromResult(new SessionConfiguration(AccountDomain, RemoteRenderingDomain, AccountId, AccountKey));
    }

    /// <summary>
    /// Keep the last used SessionID, when launching, connect to this session if its available
    /// </summary>
    private string LastUsedSessionID
    {
        get
        {
            if (!string.IsNullOrEmpty(SessionIDOverride))
                return SessionIDOverride;

            if (PlayerPrefs.HasKey("LastUsedSessionID"))
                return PlayerPrefs.GetString("LastUsedSessionID");
            else
                return null;
        }
        set
        {
            PlayerPrefs.SetString("LastUsedSessionID", value);
        }
    }

    public void Awake()
    {
        //Forward events to Unity events
        RequestingAuthorization += () => OnRequestingAuthorization?.Invoke();
        AuthorizedChanged += () => OnAuthorizationChanged?.Invoke();

        //Attach to event
        AuthorizedChanged += RemoteRenderingCoordinator_AuthorizedChanged;

        if (instance == null)
            instance = this;
        else
            Destroy(this);

        CoordinatorStateChange += AutomaticMode;

        CurrentCoordinatorState = RemoteRenderingState.NotInitialized;
    }

    private void RemoteRenderingCoordinator_AuthorizedChanged()
    {
        if (CurrentCoordinatorState != RemoteRenderingState.NotAuthorized)
            return; //This isn't valid from any other state than NotAuthorized


        //We just became authorized to connect to Azure
        InitializeSessionService();
    }

    /// <summary>
    /// Automatic mode attempts to automatically progress through the connection and loading steps. Doesn't handle error states.
    /// </summary>
    /// <param name="currentState">The current state</param>
    private async void AutomaticMode(RemoteRenderingState currentState)
    {
        if (!automaticMode)
            return;

        //Add a small delay for visual effect
        await Task.Delay(1500);
        switch (currentState)
        {
            case RemoteRenderingState.NotInitialized:
                InitializeARR();
                break;
            case RemoteRenderingState.NotAuthorized:
                RequestAuthorization();
                break;
            case RemoteRenderingState.NoSession:
                JoinRemoteSession();
                break;
            case RemoteRenderingState.RemoteSessionReady:
                ConnectRuntimeToRemoteSession();
                break;
        }
    }

    /// <summary>
    /// Initializes ARR, associating the main camera
    /// Note: This must be called on the main Unity thread
    /// </summary>
    public void InitializeARR()
    {
        //Implement me
    }

    /// <summary>
    /// Create a new remote session manager
    /// If the ARRCredentialGetter is set, use it as it, otherwise use the development credentials 
    /// </summary>
    public async void InitializeSessionService()
    {
        //Implement me
    }

    /// <summary>
    /// Trigger the event for checking authorization, respond to this event by prompting the user for authentication
    /// If authorized, set Authorized = true
    /// </summary>
    public void RequestAuthorization()
    {
        RequestingAuthorization?.Invoke();
    }

    public void BypassAuthorization()
    {
        Authorized = true;
    }

    /// <summary>
    /// Attempts to join an existing session or start a new session
    /// </summary>
    public async void JoinRemoteSession()
    {
        //Implement me
    }

    public async void StopRemoteSession()
    {
        //Implement me
    }

    private async Task<bool> IsSessionAvailable(string sessionID)
    {
        bool sessionAvailable = false;
        try
        {
            RenderingSessionPropertiesArrayResult result = await ARRSessionService.Client.GetCurrentRenderingSessionsAsync();
            if (result.ErrorCode == Result.Success)
            {
                RenderingSessionProperties[] properties = result.SessionProperties;
                if (properties != null)
                {
                    sessionAvailable = properties.Any(x => x.Id == sessionID && (x.Status == RenderingSessionStatus.Ready || x.Status == RenderingSessionStatus.Starting));
                }
            }
            else
            {
                Debug.LogError($"Failed to get current rendering sessions. Error: {result.Context.ErrorMessage}");
            }
        }
        catch (RRException ex)
        {
            Debug.LogError($"Failed to get current rendering sessions. Error: {ex.Message}");
        }
        return sessionAvailable;
    }

    /// <summary>
    /// Connects the local runtime to the current active session, if there's a session available
    /// </summary>
    public async void ConnectRuntimeToRemoteSession()
    {
        //Implement me
    }

    public void DisconnectRuntimeFromRemoteSession()
    {
        //Implement me
    }

    /// <summary>
    /// The session must have its runtime pump updated.
    /// The Connection.Update() will push messages to the server, receive messages, and update the frame-buffer with the remotely rendered content.
    /// </summary>
    private void LateUpdate()
    {
        ARRSessionService?.CurrentActiveSession?.Connection?.Update();
    }

    /// <summary>
    /// Loads a model into the remote session for rendering
    /// </summary>
    /// <param name="modelPath">The model's path</param>
    /// <param name="progress">A call back method that accepts a float progress value [0->1]</param>
    /// <param name="parent">The parent Transform for this remote entity</param>
    /// <returns>An awaitable Remote Rendering Entity</returns>
    public async Task<Entity> LoadModel(string modelPath, UnityEngine.Transform parent = null, Action<float> progress = null)
    {
        //Implement me
        return null;
    }

    private async void OnRemoteSessionStatusChanged(ARRServiceUnity caller, RenderingSession session)
    {
        var properties = await session.GetPropertiesAsync();

        switch (properties.SessionProperties.Status)
        {
            case RenderingSessionStatus.Error:
            case RenderingSessionStatus.Expired:
            case RenderingSessionStatus.Stopped:
            case RenderingSessionStatus.Unknown:
                CurrentCoordinatorState = RemoteRenderingState.NoSession;
                break;
            case RenderingSessionStatus.Starting:
                CurrentCoordinatorState = RemoteRenderingState.ConnectingToNewRemoteSession;
                break;
            case RenderingSessionStatus.Ready:
                CurrentCoordinatorState = RemoteRenderingState.RemoteSessionReady;
                break;
        }
    }

    private void OnLocalRuntimeStatusChanged(ConnectionStatus status, Result error)
    {
        switch (status)
        {
            case ConnectionStatus.Connected:
                CurrentCoordinatorState = RemoteRenderingState.RuntimeConnected;
                break;
            case ConnectionStatus.Connecting:
                CurrentCoordinatorState = RemoteRenderingState.ConnectingToRuntime;
                break;
            case ConnectionStatus.Disconnected:
                CurrentCoordinatorState = RemoteRenderingState.RemoteSessionReady;
                break;
        }
    }
}

Vytvoření objektu GameObject služby Azure Remote Rendering

Koordinátor vzdáleného vykreslování a jeho požadovaný skript (ARRServiceUnity) jsou monobehaviours, které musí být připojené k Objektu GameObject ve scéně. Skript ARRServiceUnity poskytuje ARR, který zveřejňuje většinu funkcí ARR pro připojení ke vzdáleným relacím a jejich správě.

  1. Ve scéně vytvořte nový Objekt GameObject (Ctrl+Shift+N nebo GameObject-Create> Empty) a pojmenujte ho RemoteRenderingCoordinator.
  2. Přidejte skript RemoteRenderingCoordinator do objektu GameObject RemoteRenderingCoordinator.
    Snímek obrazovky s dialogovým oknem Přidat komponentu Unity Vyhledávací textové pole obsahuje text RemoteRenderingCoordinator.
  3. Potvrďte, že se skript ARRServiceUnity, který se v inspektoru zobrazuje jako Služba, se automaticky přidá do Objektu GameObject. V případě, že vás zajímá, je to výsledek [RequireComponent(typeof(ARRServiceUnity))] v horní části skriptu RemoteRenderingCoordinator .
  4. Přidejte přihlašovací údaje služby Azure Remote Rendering, doménu účtu a doménu vzdáleného vykreslování do koordinačního skriptu:
    Snímek obrazovky inspektoru Unity skriptu koordinátoru vzdáleného vykreslování Pole pro zadání přihlašovacích údajů jsou zvýrazněná.

Inicializace služby Azure Remote Rendering

Teď, když máme architekturu pro našeho koordinátora, budeme implementovat každou ze čtyř fází počínaje inicializací vzdáleného vykreslování.

Diagram čtyř fází potřebných k načtení modelu První fáze Inicializace vzdáleného vykreslování je zvýrazněná.

Inicializace říká službě Azure Remote Rendering, který objekt fotoaparátu se má použít k vykreslování a průběhu stavového počítače do NotAuthorized. Tento stav znamená, že se inicializuje, ale ještě nemá oprávnění připojit se k relaci. Vzhledem k tomu, že spuštění relace ARR způsobuje náklady, musíme ověřit, že chce uživatel pokračovat.

Při zadávání notAuthorized stavu se volá CheckAuthorization , která vyvolá událost RequestingAuthorization a určí, které přihlašovací údaje účtu použít (AccountInfo je definován v horní části třídy a používá přihlašovací údaje, které jste definovali pomocí Unity Inspector v kroku výše).

Poznámka:

ARR nepodporuje rekompilace za běhu. Úprava skriptu a jeho uložení v době, kdy je aktivní režim přehrávání, může vést k tomu, že Unity zamrzne a bude nutné vynutit vypnutí prostřednictvím správce úloh. Před úpravou skriptů se vždy ujistěte, že jste zastavili režim přehrávání.

  1. Nahraďte obsah InitializeARR a InitializeSessionService vyplněným kódem níže:

    /// <summary>
    /// Initializes ARR, associating the main camera
    /// Note: This must be called on the main Unity thread
    /// </summary>
    public void InitializeARR()
    {
        RemoteManagerUnity.InitializeManager(new RemoteUnityClientInit  (Camera.main));
    
        CurrentCoordinatorState = RemoteRenderingState.NotAuthorized;
    }
    
    /// <summary>
    /// Create a new remote session manager
    /// If the ARRCredentialGetter is set, use it as it, otherwise use  the development credentials 
    /// </summary>
    public async void InitializeSessionService()
    {
        if (ARRCredentialGetter == null)
            ARRCredentialGetter = GetDevelopmentCredentials;
    
        var sessionConfiguration = await ARRCredentialGetter.Invoke();
    
        ARRSessionService.OnSessionStatusChanged +=     OnRemoteSessionStatusChanged;
    
        try
        {
            ARRSessionService.Initialize(sessionConfiguration);
        }
        catch (ArgumentException argumentException)
        {
            Debug.LogError(argumentException.Message);
            CurrentCoordinatorState = RemoteRenderingState. NotAuthorized;
            return;
        }
    
        CurrentCoordinatorState = RemoteRenderingState.NoSession;
    }
    

Abychom mohli pokračovat z NotAuthorized na NoSession, obvykle bychom uživateli představili modální dialogové okno, aby si mohli vybrat (a to děláme jen v jiné kapitole). Prozatím automaticky vynecháme autorizační kontrolu voláním ByPassAuthentication, jakmile se aktivuje událost RequestingAuthorization.

  1. Vyberte RemoteRenderingCoordinator GameObject a najděte událost OnRequestingAuthorization Unity vystavenou v inspektoru komponenty RemoteRenderingCoordinator.

  2. Přidejte novou událost stisknutím klávesy +v pravém dolním rohu.

  3. Přetáhněte komponentu na vlastní událost, aby odkazovala sama na sebe. Snímek obrazovky inspektoru Unity skriptu koordinátoru vzdáleného vykreslování Záhlaví komponenty je zvýrazněné a šipka ji připojí k události Při vyžádání autorizace.

  4. V rozevíracím seznamu vyberte RemoteRenderingCoordinator –> BypassAuthorization.
    Snímek obrazovky s událostí Při vyžádání autorizace

Vytvoření vzdálené relace nebo připojení k ní

Druhou fází je vytvoření relace vzdáleného vykreslování nebo připojení k ní (další informace o relacích vykreslování najdete v tématu Relace vzdáleného vykreslování).

Diagram čtyř fází potřebných k načtení modelu Ve druhé fázi je zvýrazněná možnost Vytvořit nebo připojit se k relaci vzdáleného vykreslování.

Vzdálená relace je místo, kde se modely vykreslují. Metoda JoinRemoteSession( ) se pokusí připojit k existující relaci, sledovat pomocí Vlastnosti LastUsedSessionID nebo pokud je přiřazené ID aktivní relace na SessionIDOverride. SessionIDOverride je určený jenom pro účely ladění, měl by se používat jenom v případě, že víte, že relace existuje a chcete se k ní explicitně připojit.

Pokud nejsou k dispozici žádné relace, vytvoří se nová relace. Vytvoření nové relace je ale časově náročná operace. Proto byste se měli pokusit vytvořit relace pouze v případě potřeby a kdykoli je to možné (viz Komerční připraveno: Sdružování relací, plánování a osvědčené postupy pro další informace o správě relací).

Tip

StopRemoteSession() ukončí aktivní relaci. Pokud chcete zabránit zbytečným poplatkům, měli byste relace vždy zastavit, když už nejsou potřeba.

Stavový počítač teď bude v závislosti na dostupných relacích pokračovat na Připojení ingToNewRemoteSession nebo Připojení ingToExistingRemoteSession. Otevření existující relace nebo vytvoření nové relace aktivují událost ARRSessionService.OnSessionStatusChanged , která spouští naši metodu OnRemoteSessionStatusChanged . V ideálním případě to vede k postupu stavového počítače na RemoteSessionReady.

  1. Pokud se chcete připojit k nové relaci, upravte kód tak, aby nahradil metody JoinRemoteSession( ) a StopRemoteSession( ) dokončenými příklady níže:
/// <summary>
/// Attempts to join an existing session or start a new session
/// </summary>
public async void JoinRemoteSession()
{
    //If there's a session available that previously belonged to us, and it's ready, use it. Otherwise start a new session.
    RenderingSessionProperties joinResult;
    if (await IsSessionAvailable(LastUsedSessionID))
    {
        CurrentCoordinatorState = RemoteRenderingState.ConnectingToExistingRemoteSession;
        joinResult = await ARRSessionService.OpenSession(LastUsedSessionID);
    }
    else
    {
        CurrentCoordinatorState = RemoteRenderingState.ConnectingToNewRemoteSession;
        joinResult = await ARRSessionService.StartSession(new RenderingSessionCreationOptions(renderingSessionVmSize, (int)maxLeaseHours, (int)maxLeaseMinutes));
    }

    if (joinResult.Status == RenderingSessionStatus.Ready || joinResult.Status == RenderingSessionStatus.Starting)
    {
        LastUsedSessionID = joinResult.Id;
    }
    else
    {
        //The session should be ready or starting, if it's not, something went wrong
        await ARRSessionService.StopSession();
        if(LastUsedSessionID == SessionIDOverride)
            SessionIDOverride = "";
        CurrentCoordinatorState = RemoteRenderingState.NoSession;
    }
}

public async void StopRemoteSession()
{
    if (ARRSessionService.CurrentActiveSession != null)
    {
        await ARRSessionService.CurrentActiveSession.StopAsync();
    }
}

Pokud chcete ušetřit čas opakovaným použitím relací, nezapomeňte deaktivovat možnost Automaticky zastavit relaci v komponentě ARRServiceUnity . Mějte na paměti, že to nechá relace spuštěné, i když k nim nikdo není připojený. Vaše relace může běžet tak dlouho, dokud se maxLeaseTime před vypnutím serverem (hodnotu MaxLeaseTime lze upravit v koordinátoru vzdáleného vykreslování v části Nové výchozí hodnoty relace). Pokud na druhou stranu automaticky vypnete každou relaci při odpojení, budete muset počkat, až se nová relace spustí pokaždé, což může být zdlouhavý proces.

Poznámka:

Zastavení relace se projeví okamžitě a nelze ji vrátit zpět. Po zastavení musíte vytvořit novou relaci se stejnou režií při spuštění.

Připojení místní modul runtime do vzdálené relace

V dalším kroku musí aplikace připojit místní modul runtime ke vzdálené relaci.

Diagram čtyř fází potřebných k načtení modelu Třetí fáze

Aplikace také potřebuje naslouchat událostem týkajícím se připojení mezi modulem runtime a aktuální relací; tyto změny stavu jsou zpracovávány v OnLocalRuntimeStatusChanged. Tento kód přejde do našeho stavu na Připojení ingToRuntime. Po připojení v OnLocalRuntimeStatusChanged přejde stav do modulu Runtime Připojení ed. Připojení do modulu runtime je posledním stavem, se kterým se koordinátor zabývá, což znamená, že aplikace se provádí se všemi běžnými konfiguracemi a je připravena zahájit práci na načítání a vykreslování modelů specifických pro relaci.

  1. Nahraďte metody Připojení RuntimeToRemoteSession( ) a DisconnectRuntimeFromRemoteSession( ) dokončenými verzemi níže.
  2. Je důležité si uvědomit metodu Unity LateUpdate a že aktualizuje aktuální aktivní relaci. To umožňuje aktuální relaci odesílat a přijímat zprávy a aktualizovat vyrovnávací paměť rámce pomocí rámců přijatých ze vzdálené relace. Správné fungování ARR je důležité.
/// <summary>
/// Connects the local runtime to the current active session, if there's a session available
/// </summary>
public async void ConnectRuntimeToRemoteSession()
{
    if (ARRSessionService == null || ARRSessionService.CurrentActiveSession == null)
    {
        Debug.LogError("Not ready to connect runtime");
        return;
    }

    // Connect the local runtime to the currently connected session
    // This session is set when connecting to a new or existing session

    ARRSessionService.CurrentActiveSession.ConnectionStatusChanged += OnLocalRuntimeStatusChanged;
    await ARRSessionService.CurrentActiveSession.ConnectAsync(new RendererInitOptions());
}

public void DisconnectRuntimeFromRemoteSession()
{
    if (ARRSessionService == null || ARRSessionService.CurrentActiveSession == null || ARRSessionService.CurrentActiveSession.ConnectionStatus != ConnectionStatus.Connected)
    {
        Debug.LogError("Runtime not connected!");
        return;
    }

    ARRSessionService.CurrentActiveSession.Disconnect();
    ARRSessionService.CurrentActiveSession.ConnectionStatusChanged -= OnLocalRuntimeStatusChanged;
    CurrentCoordinatorState = RemoteRenderingState.RemoteSessionReady;
}

Poznámka:

Připojení místního modulu runtime do vzdálené relace závisí na Aktualizace, která se volá v aktuálně aktivní relaci. Pokud zjistíte, že aplikace nikdy nepostupuje za stav Připojení ingToRuntime, ujistěte se, že v aktivní relaci pravidelně voláte aktualizaci.

Načtení modelu

S požadovaným základem jste připraveni načíst model do vzdálené relace a začít přijímat rámce.

Diagram čtyř fází potřebných k načtení modelu Je zvýrazněná čtvrtá fáze Načtení a zobrazení modelu.

Metoda LoadModel je navržená tak, aby přijímala cestu modelu, obslužnou rutinu průběhu a nadřazenou transformaci. Tyto argumenty slouží k načtení modelu do vzdálené relace, aktualizaci uživatele při načítání průběhu a orientaci vzdáleně vykresleného modelu na základě nadřazené transformace.

  1. Metodu LoadModel zcela nahraďte následujícím kódem:

    /// <summary>
    /// Loads a model into the remote session for rendering
    /// </summary>
    /// <param name="modelName">The model's path</param>
    /// <param name="parent">The parent Transform for this remote entity</param>
    /// <param name="progress">A call back method that accepts a float progress value [0->1]</param>
    /// <returns>An awaitable Remote Rendering Entity</returns>
    public async Task<Entity> LoadModel(string modelPath, UnityEngine.Transform parent = null, Action<float> progress = null)
    {
        //Create a root object to parent a loaded model to
        var modelEntity = ARRSessionService.CurrentActiveSession.Connection.CreateEntity();
    
        //Get the game object representation of this entity
        var modelGameObject = modelEntity.GetOrCreateGameObject(UnityCreationMode.DoNotCreateUnityComponents);
    
        //Ensure the entity will sync its transform with the server
        var sync = modelGameObject.GetComponent<RemoteEntitySyncObject>();
        sync.SyncEveryFrame = true;
    
        //Parent the new object under the defined parent
        if (parent != null)
        {
            modelGameObject.transform.SetParent(parent, false);
            modelGameObject.name = parent.name + "_Entity";
        }
    
        //Load a model that will be parented to the entity
        var loadModelParams = new LoadModelFromSasOptions(modelPath, modelEntity);
        var loadModelAsync = ARRSessionService.CurrentActiveSession.Connection.LoadModelFromSasAsync(loadModelParams, progress);
        var result = await loadModelAsync;
        return modelEntity;
    }
    

Výše uvedený kód provádí následující kroky:

  1. Vytvořte vzdálenou entitu.
  2. Vytvořte místní objekt GameObject, který bude představovat vzdálenou entitu.
  3. Nakonfigurujte místní GameObject tak, aby synchronizoval svůj stav (tj. Transformovat) se vzdálenou entitou při každém snímku.
  4. Načtěte data modelu ze služby Blob Storage do vzdálené entity.
  5. Vrátí nadřazenou entitu pro pozdější referenci.

Zobrazení testovacího modelu

Teď máme veškerý kód potřebný k zobrazení vzdáleně vykresleného modelu, všechny čtyři požadované fáze vzdáleného vykreslování jsou hotové. Teď potřebujeme přidat trochu kódu, abychom mohli zahájit proces načítání modelu.

Diagram čtyř fází potřebných k načtení modelu Všechny fáze jsou označené jako dokončené.

  1. Do třídy RemoteRenderingCoordinator přidejte následující kód, těsně pod metodu LoadModel je v pořádku:

    private bool loadingTestModel = false;
    [ContextMenu("Load Test Model")]
    public async void LoadTestModel()
    {
        if(CurrentCoordinatorState != RemoteRenderingState.RuntimeConnected)
        {
            Debug.LogError("Please wait for the runtime to connect before loading the test model. Try again later.");
            return;
        }
        if(loadingTestModel)
        {
            Debug.Log("Test model already loading or loaded!");
            return;
        }
        loadingTestModel = true;
    
        // Create a parent object to use for positioning
        GameObject testParent = new GameObject("TestModelParent");
        testParent.transform.position = new Vector3(0f, 0f, 3f);
    
        // The 'built in engine path' is a special path that references a test model built into Azure Remote Rendering.
        await LoadModel("builtin://Engine", testParent.transform, (progressValue) => Debug.Log($"Loading Test Model progress: {Math.Round(progressValue * 100, 2)}%"));
    }
    

    Tento kód vytvoří GameObject, který bude fungovat jako nadřazený testovací model. Potom volá metodu LoadModel , která načte model "builtin://Engine", což je prostředek integrovaný do služby Azure Remote Rendering pro účely testování vykreslování.

  2. Uložte kód.

  3. Stisknutím tlačítka Přehrát v Unity Editoru spusťte proces připojení ke službě Azure Remote Rendering a vytvoření nové relace.

  4. V zobrazení Hry se ale moc nezobrazí, konzola zobrazuje stav aplikace, která se mění. Bude pravděpodobně pokračovat ConnectingToNewRemoteSessiona zůstat tam, možná až pět minut.

  5. Výběrem objektu GameObject RemoteRenderingCoordinator zobrazíte jeho připojené skripty v inspektoru. Sledujte, jak komponenta služby prochází inicializací a kroky připojení.

  6. Monitorujte výstup konzoly – čeká se na změnu stavu na modul runtime Připojení ed.

  7. Po připojení modulu runtime klikněte pravým tlačítkem na RemoteRenderingCoordinator v inspektoru a otevřete tak místní nabídku. Potom v místní nabídce vyberte možnost Zátěžový testovací model přidanou [ContextMenu("Load Test Model")] částí našeho kódu výše.

    Snímek obrazovky inspektoru Unity skriptu koordinátoru vzdáleného vykreslování. Zvýrazní pokyn, aby nejprve klikl pravým tlačítkem na záhlaví a pak v místní nabídce vyberte Načíst testovací model.

  8. Sledujte konzolu pro výstup ProgressHandler , který jsme předali do metody LoadModel .

  9. Podívejte se na vzdáleně vykreslený model!

Poznámka:

Vzdálený model nebude nikdy viditelný v zobrazení scény, pouze v zobrazení hry. Důvodem je, že ARR vykresluje snímky vzdáleně speciálně pro perspektivu kamery herního zobrazení a nezná kameru Editoru (používá se k vykreslení zobrazení scény).

Další kroky

Snímek obrazovky Unity se spuštěným projektem v režimu přehrávání Motor auta se vykresluje uprostřed výřezu.

Gratulujeme! Vytvořili jste základní aplikaci, která dokáže zobrazit vzdáleně vykreslené modely pomocí Azure Remote Renderingu. V dalším kurzu integrujeme MRTK a naimportujeme vlastní modely.