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í

Předpoklady

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.

Screenshot of Unity Hub showing the Create a New Unity Project dialog. The panel 3D is selected.

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 :

    Screenshot of the Unity inspector for a Transform component. The context menu is opened and Reset is selected.

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

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

    Screenshot of the Unity Color wheel dialog. The color is set to 0 for all R G B A components.

  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ů.

    Screenshot of the Unity inspector for a Camera component.

Ú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.

      Screenshot of the Unity Project Settings dialog. The Quality entry is selected in the list on the left. The context menu for the default quality level is opened on the right. The low entry is selected.

    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.

    Screenshot of the Unity Project Settings dialog. The XR Plug-in Management entry is selected in the list on the left. The tab with the windows logo is highlighted on the right. The Open XR checkbox below it is also highlighted.

    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

    Screenshot of the Unity Project Settings dialog. The Open XR subentry is selected in the list on the left. Highlights on the right side are placed on the Depth Submission Mode, Interaction Profiles, and Open XR feature settings.

    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á. Screenshot of the Unity Project Settings dialog. The Player entry is selected in the list on the left. Highlights on the right side are placed on the tab with the Windows logo, the Color Space setting, and the Active input Handling setting.
    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 DesktopScreenshot of the Unity Project Settings dialog. The Player entry is selected in the list on the left. Highlights on the right side are placed on the Capabilities and the Supported Device Families settings.
  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.
      Screenshot of the Unity Build Settings dialog. The Universal Windows Platform entry is selected in the list on the left. Highlights on the right side are placed on the settings dropdown boxes and the Switch Platform button.
  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.

    Screenshot of the Unity Project Validator dialog. The dialog shows a list of required, recommended, and development rules that are all successful checked.

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 of the four stages required to load a model.

  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:

    Screenshot of Unity Project hierarchy containing the new script.

    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.
    Screenshot of the Unity Add Component dialog. The search text field contains the 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:
    Screenshot of the Unity inspector of the Remote Rendering Coordinator Script. The credential input fields are highlighted.

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 of the four stages required to load a model. The first stage

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. Screenshot of the Unity inspector of the Remote Rendering Coordinator Script. The title bar of the component is highlighted and an arrow connects it to the On Requesting Authorization event.

  4. V rozevíracím seznamu vyberte RemoteRenderingCoordinator –> BypassAuthorization.
    Screenshot of the On Requesting Authorization event.

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 of the four stages required to load a model. The second stage

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 of the four stages required to load a model. The third stage

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 of the four stages required to load a model. The fourth stage

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 of the four stages required to load a model. All stages are marked as completed.

  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.

    Screenshot of the Unity inspector of the Remote Rendering Coordinator Script. Highlights instruct to first right-click on the title bar and then select Load Test Model from the context menu.

  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

Screenshot of Unity running the project in Play mode. A car engine is rendered in the center of the viewport.

Blahopřejeme! 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.