Dela via


Självstudie: Visa en fjärrre renderad modell

I den här självstudien lär du dig att:

  • Etablera en Instans av Azure Remote Rendering (ARR)
  • Skapa och stoppa en renderingssession
  • Återanvänd en befintlig återgivningssession
  • Anslut och koppla från sessioner
  • Läsa in modeller i en renderingssession

Förutsättningar

För den här självstudien behöver du:

  • En aktiv Betala per användning Azure-prenumeration Skapa ett konto
  • Windows SDK 10.0.18362.0 (ladda ned)
  • Den senaste versionen av Visual Studio 2022 (ladda ned)
  • Git (ladda ned)
  • Git LFS-plugin-program (ladda ned)
  • Unity (se systemkrav för versioner som stöds)
  • Mellanliggande kunskaper om Unity och C#-språket (till exempel att skapa skript och objekt, använda prefabs, konfigurera Unity-händelser osv.)

Etablera en Instans av Azure Remote Rendering (ARR)

För att få åtkomst till Azure Remote Rendering-tjänsten måste du först skapa ett konto.

Skapa ett nytt Unity-projekt

Dricks

ARR-exempellagringsplatsen innehåller ett projekt där alla självstudier har slutförts. Den kan användas som referens. Titta i Unity\Tutorial-Complete för det fullständiga Unity-projektet.

Skapa ett nytt projekt från Unity Hub. I det här exemplet antar vi att projektet skapas i en mapp med namnet RemoteRendering.

Skärmbild av Unity Hub som visar dialogrutan Skapa ett nytt Unity-projekt. Panelens 3D är markerad.

Inkludera Azure Remote Rendering- och OpenXR-paketen

Följ anvisningarna om hur du lägger till Azure Remote Rendering- och OpenXR-paketen i Ditt Unity-projekt.

Kommentar

Om Unity visar en varningsdialogruta när du har importerat OpenXR-paketet och frågat om du vill aktivera de interna plattformsserverdelarna för det nya indatasystemet klickar du på Nej för tillfället. Du aktiverar det i ett senare steg.

Konfigurera kameran

  1. Välj noden Main Kamera.

  2. Öppna snabbmenyn genom att högerklicka på transformeringskomponenten och välj alternativet Återställ :

    Skärmbild av Unity-inspektören för en transformeringskomponent. Snabbmenyn öppnas och Återställ har valts.

  3. Ange Rensa flaggor till Solid Color

  4. Ange Bakgrund till Svart (#0000000), med helt transparent (0) alfa (A)

    Skärmbild av dialogrutan Unity Color Wheel. Färgen är inställd på 0 för alla R G B A-komponenter.

  5. Ange Urklippsplan till Nära = 0,1 och Far = 20. Den här installationen innebär återgivning av klippgeometri som är närmare än 10 cm eller längre än 20 meter.

    Skärmbild av Unity-inspektören för en Kamera komponent.

Justera projektinställningarna

  1. Öppna Redigera > projekt Inställningar...

  2. Välj Kvalitet på den vänstra listmenyn

    1. Ändra standardkvalitetsnivån för alla plattformar till Låg. Den här inställningen möjliggör effektivare återgivning av lokalt innehåll och påverkar inte kvaliteten på fjärråtergivet innehåll.

      Skärmbild av dialogrutan Unity Project Inställningar. Posten Kvalitet är markerad i listan till vänster. Snabbmenyn för standardkvalitetsnivån öppnas till höger. Den låga posten är markerad.

    Kommentar

    I omfånget för den här självstudien håller vi oss till den inbyggda pipelinen för Unity-återgivning. Om du vill använda den universella återgivningspipelinen kan du läsa Unity Render Pipelines (Unity Render Pipelines ) för ytterligare konfigurationssteg.

  3. Välj XR Plugin Management på menyn till vänster i listan

    1. Klicka på knappen Installera XR-plugin-hantering .
    2. Välj fliken Universell Windows-plattform inställningar, som visas som en Windows-ikon.
    3. Markera kryssrutan Öppna XR under Plugin-leverantörer
    4. Om en dialogruta öppnas där du uppmanas att aktivera de inbyggda plattformsserverdelarna för det nya indatasystemet väljer du Nej.

    Skärmbild av dialogrutan Unity Project Inställningar. Posten XR Plug-in Management är markerad i listan till vänster. Fliken med Windows-logotypen är markerad till höger. Kryssrutan Öppna XR nedan är också markerad.

    Kommentar

    Om microsoft HoloLens-funktionsgruppen är inaktiverad saknas Windows Mixed Reality OpenXR-plugin-programmet i projektet. Följ anvisningarna om hur du lägger till Azure Remote Rendering- och OpenXR-paketen för att installera det.

  4. Välj OpenXR på menyn till vänster i listan

    1. Ange djupöverföringsläge till Djup 16 bitar
    2. Lägg till Microsoft Hand Interaction Profile i Interaktionsprofiler.
    3. Aktivera dessa OpenXR-funktioner:
      • Azure Remote Rendering
      • Handspårning
      • Funktioner för mixad verklighet
      • Rörelsestyrenhetsmodell

    Skärmbild av dialogrutan Unity Project Inställningar. Underförsöket Öppna XR är markerat i listan till vänster. Markeringar till höger placeras i djupöverföringsläget, interaktionsprofiler och funktionsinställningarna Öppna XR.

    Kommentar

    Om du inte ser de nödvändiga OpenXR-funktionerna i listan saknas Windows Mixed Reality OpenXR-plugin-programmet från projektet. Följ anvisningarna om hur du lägger till Azure Remote Rendering- och OpenXR-paketen för att installera det.

  5. Välj Spelare i den vänstra listmenyn

    1. Välj fliken Universell Windows-plattform inställningar, som visas som en Windows-ikon.
    2. Expandera andra Inställningar
    3. Under Rendering ändrar du Färgrymd till Linjär och startar om Unity när du uppmanas att göra det.
    4. Under Konfiguration ändrar du Aktiv indatahantering till Båda och startar om Unity när du uppmanas att göra det. Skärmbild av dialogrutan Unity Project Inställningar. Posten Spelare är markerad i listan till vänster. Markeringar till höger placeras på fliken med Windows-logotypen, inställningen Färgutrymme och inställningen Aktiv indatahantering.
    5. Expandera Publicering Inställningar
    6. Rulla ned till Funktioner och välj:
      • InternetClient
      • InternetClientServer
      • SpatialPerception
      • PrivateNetworkClientServer (valfritt). Välj det här alternativet om du vill ansluta unity-fjärrfelsökaren till enheten.
    7. Under Enhetsfamiljer som stöds aktiverar du Holographic and DesktopSkärmbild av dialogrutan Unity Project Inställningar. Posten Spelare är markerad i listan till vänster. Markeringar till höger placeras i inställningarna Funktioner och Enhetsfamiljer som stöds.
  6. Stäng eller docka panelen Project Inställningar

  7. Öppna Inställningar>

    1. Välj Universell Windows-plattform
    2. Konfigurera inställningarna så att de matchar de som finns nedan
    3. Tryck på knappen Växla plattform .
      Skärmbild av dialogrutan Unity Build Inställningar. Posten Universell Windows-plattform är markerad i listan till vänster. Markeringar till höger placeras i listrutorna för inställningar och knappen Växla plattform.
  8. När Unity har ändrat plattformar stänger du byggpanelen.

Verifiera projektkonfigurationen

Utför följande steg för att kontrollera att projektinställningarna är korrekta.

  1. Välj posten ValidateProject från RemoteRendering-menyn i verktygsfältet i Unity-redigeraren.

  2. I fönstret Projektverifierare finns fel och åtgärda projektinställningar där det behövs.

    Skärmbild av dialogrutan Unity Project Validator. Dialogrutan visar en lista över obligatoriska, rekommenderade och utvecklingsregler som alla har markerats.

Kommentar

Om du använder MRTK i projektet och aktiverar kameraundersystemet åsidosätter MRTK manuella ändringar som du tillämpar på kameran. Detta inkluderar korrigeringar från verktyget ValidateProject.

Skapa ett skript för att samordna anslutning och tillstånd för Azure Remote Rendering

Det finns fyra grundläggande steg för att visa fjärranslutna modeller som beskrivs i flödesschemat nedan. Varje steg måste utföras i ordning. Nästa steg är att skapa ett skript som hanterar programtillståndet och gå igenom varje steg som krävs.

Diagram över de fyra steg som krävs för att läsa in en modell.

  1. I fönstret Projekt under Tillgångar skapar du en ny mapp med namnet RemoteRenderingCore. I RemoteRenderingCore skapar du sedan en annan mapp med namnet Skript.

  2. Skapa ett nytt C#-skript med namnet RemoteRenderingCoordinator. Projektet bör se ut så här:

    Skärmbild av Unity Project-hierarkin som innehåller det nya skriptet.

    Det här koordinatorskriptet spårar och hanterar fjärråtergivningstillståndet. Observera att en del av den här koden används för att underhålla tillstånd, exponera funktioner för andra komponenter, utlösa händelser och lagra programspecifika data som inte är direkt relaterade till Azure Remote Rendering. Använd koden nedan som utgångspunkt så tar vi itu med och implementerar den specifika Azure Remote Rendering-koden senare i självstudien.

  3. Öppna RemoteRenderingCoordinator i kodredigeraren och ersätt hela innehållet med koden nedan:

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

Skapa Azure Remote Rendering GameObject

Fjärrrenderingskoordinatorn och dess nödvändiga skript (ARRServiceUnity) är båda MonoBehaviours som måste kopplas till en GameObject i scenen. ARRServiceUnity-skriptet tillhandahålls av ARR för att exponera mycket av ARR:s funktioner för att ansluta till och hantera fjärrsessioner.

  1. Skapa en ny GameObject i scenen (Ctrl+Skift+N eller GameObject-Create> Empty) och ge den namnet RemoteRenderingCoordinator.
  2. Lägg till RemoteRenderingCoordinator-skriptet i RemoteRenderingCoordinator GameObject.
    Skärmbild av dialogrutan Lägg till komponent i Unity. Söktextfältet innehåller texten RemoteRenderingCoordinator.
  3. Bekräfta att SKRIPTet ARRServiceUnity , som visas som Tjänst i inspektören, läggs till automatiskt i GameObject. Om du undrar är detta ett resultat [RequireComponent(typeof(ARRServiceUnity))] överst i RemoteRenderingCoordinator-skriptet .
  4. Lägg till dina autentiseringsuppgifter för Azure Remote Rendering, kontodomänen och fjärrrenderingsdomänen i koordinatorskriptet:
    Skärmbild av Unity-inspektören för skriptet fjärrrenderingskoordinator. Indatafälten för autentiseringsuppgifter är markerade.

Initiera Azure Remote Rendering

Nu när vi har ramverket för vår koordinator implementerar vi vart och ett av de fyra stegen som börjar med Initiera fjärrrendering.

Diagram över de fyra steg som krävs för att läsa in en modell. Den första fasen

Initiera talar om för Azure Remote Rendering vilket kameraobjekt som ska användas för rendering och förlopp för tillståndsdatorn till Ej auktoriserad. Det här tillståndet innebär att det har initierats men ännu inte har behörighet att ansluta till en session. Eftersom det medför en kostnad att starta en ARR-session måste vi bekräfta att användaren vill fortsätta.

När du anger tillståndet Ej auktoriserad anropas CheckAuthorization, som anropar händelsen RequestingAuthorization och avgör vilka kontoautentiseringsuppgifter som ska användas (AccountInfo definieras nära toppen av klassen och använder de autentiseringsuppgifter som du definierade via Unity Inspector i steget ovan).

Kommentar

Omkompilering av körning stöds inte av ARR. Om du ändrar skriptet och sparar det medan uppspelningsläget är aktivt kan det leda till att Unity fryser och behöver tvinga fram avstängning via aktivitetshanteraren. Se alltid till att du har stoppat uppspelningsläget innan du redigerar skripten.

  1. Ersätt innehållet i InitializeARR och InitializeSessionService med den färdiga koden nedan:

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

För att kunna gå vidare från NotAuthorized till NoSession skulle vi vanligtvis presentera en modal dialogruta för användaren så att de kan välja (och vi gör just det i ett annat kapitel). För tillfället kringgår vi automatiskt auktoriseringskontrollen genom att anropa ByPassAuthentication så snart händelsen RequestingAuthorization utlöses.

  1. Välj RemoteRenderingCoordinator GameObject och leta reda på händelsen OnRequestingAuthorization Unity som exponeras i inspektören för Komponenten RemoteRenderingCoordinator.

  2. Lägg till en ny händelse genom att trycka på +i det nedre högra hörnet.

  3. Dra komponenten till en egen händelse för att referera till sig själv. Skärmbild av Unity-inspektören för skriptet fjärrrenderingskoordinator. Namnlisten för komponenten är markerad och en pil ansluter den till händelsen Vid begäran om auktorisering.

  4. I listrutan väljer du RemoteRenderingCoordinator –> BypassAuthorization.
    Skärmbild av händelsen Vid begäran om auktorisering.

Skapa eller ansluta till en fjärrsession

Det andra steget är att skapa eller ansluta till en fjärrrenderingssession (mer information om renderingssessioner finns i Fjärrrenderingssessioner).

Diagram över de fyra steg som krävs för att läsa in en modell. Den andra fasen

Fjärrsessionen är där modellerna återges. Metoden JoinRemoteSession( ) försöker ansluta till en befintlig session, spåras med egenskapen LastUsedSessionID eller om det finns ett tilldelat aktivt sessions-ID på SessionIDOverride. SessionIDOverride är endast avsett för felsökning. Det bör endast användas när du vet att sessionen finns och uttryckligen vill ansluta till den.

Om inga sessioner är tillgängliga skapas en ny session. Att skapa en ny session är dock en tidskrävande åtgärd. Därför bör du bara försöka skapa sessioner när det behövs och återanvända dem när det är möjligt (se Kommersiellt redo: Sessionspooler, schemaläggning och metodtips för mer information om hur du hanterar sessioner).

Dricks

StopRemoteSession() avslutar den aktiva sessionen. För att förhindra onödiga avgifter bör du alltid stoppa sessioner när de inte längre behövs.

Tillståndsdatorn fortsätter nu till antingen Anslut ingToNewRemoteSession eller Anslut ingToExistingRemoteSession, beroende på tillgängliga sessioner. Båda öppnar en befintlig session eller skapar en ny session utlöser händelsen ARRSessionService.OnSessionStatusChanged och kör vår OnRemoteSessionStatusChanged-metod . I bästa fall leder detta till att tillståndsdatorn avanceras till RemoteSessionReady.

  1. Om du vill ansluta till en ny session ändrar du koden för att ersätta metoderna JoinRemoteSession( ) och StopRemoteSession( ) med de färdiga exemplen nedan:
/// <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();
    }
}

Om du vill spara tid genom att återanvända sessioner måste du inaktivera alternativet Automatisk stoppsession i ARRServiceUnity-komponenten . Tänk på att detta lämnar sessioner igång, även när ingen är ansluten till dem. Sessionen kan köras så länge som MaxLeaseTime innan den stängs av av servern (värdet för MaxLeaseTime kan ändras i koordinatorn för fjärrrendering under Standardinställningar för ny session). Om du å andra sidan automatiskt stänger av varje session när du kopplar från måste du vänta tills en ny session startas varje gång, vilket kan vara en lång process.

Kommentar

Om du stoppar en session börjar det gälla omedelbart och kan inte ångras. När den har stoppats måste du skapa en ny session med samma startkostnader.

Anslut den lokala körningen till fjärrsessionen

Därefter måste programmet ansluta sin lokala körning till fjärrsessionen.

Diagram över de fyra steg som krävs för att läsa in en modell. Den tredje fasen

Programmet måste också lyssna efter händelser om anslutningen mellan körningen och den aktuella sessionen. dessa tillståndsändringar hanteras i OnLocalRuntimeStatusChanged. Den här koden avancerar vårt tillstånd till Anslut ingToRuntime. När tillståndet är anslutet i OnLocalRuntimeStatusChanged går det vidare till Runtime Anslut ed. Anslut till körningen är det sista tillstånd som koordinatorn har problem med, vilket innebär att programmet är klart med all gemensam konfiguration och är redo att påbörja det sessionsspecifika arbetet med inläsning och återgivning av modeller.

  1. Ersätt metoderna Anslut RuntimeToRemoteSession( ) och DisconnectRuntimeFromRemoteSession( ) med de färdiga versionerna nedan.
  2. Det är viktigt att notera Unity-metoden LateUpdate och att den uppdaterar den aktuella aktiva sessionen. På så sätt kan den aktuella sessionen skicka/ta emot meddelanden och uppdatera bildrutebufferten med de ramar som tas emot från fjärrsessionen. Det är viktigt att ARR fungerar korrekt.
/// <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;
}

Kommentar

Anslut den lokala körningen till en fjärrsession beror på Uppdatering anropas på den aktiva sessionen. Om du upptäcker att ditt program aldrig går förbi tillståndet Anslut ingToRuntime kontrollerar du att du anropar Uppdatera regelbundet på den aktiva sessionen.

Läsa in en modell

Med den nödvändiga grunden på plats är du redo att läsa in en modell i fjärrsessionen och börja ta emot ramar.

Diagram över de fyra steg som krävs för att läsa in en modell. Den fjärde fasen

Metoden LoadModel är utformad för att acceptera en modellsökväg, förloppshanterare och överordnad transformering. Dessa argument används för att läsa in en modell i fjärrsessionen, uppdatera användaren om inläsningsförloppet och orientera den fjärranslutna modellen baserat på den överordnade transformeringen.

  1. Ersätt metoden LoadModel helt med koden nedan:

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

Koden ovan utför följande steg:

  1. Skapa en fjärrentitet.
  2. Skapa en lokal GameObject för att representera fjärrentiteten.
  3. Konfigurera den lokala GameObject för att synkronisera dess tillstånd (det vill säga Transformera) till fjärrentiteten varje bildruta.
  4. Läs in modelldata från Blob Storage till fjärrentiteten.
  5. Returnera den överordnade entiteten för senare referens.

Visa testmodellen

Nu har vi all kod som krävs för att visa en fjärråtergiven modell. Alla fyra faser som krävs för fjärrrendering har slutförts. Nu måste vi lägga till lite kod för att starta modellinläsningsprocessen.

Diagram över de fyra steg som krävs för att läsa in en modell. Alla steg markeras som slutförda.

  1. Lägg till följande kod i klassen RemoteRenderingCoordinator , precis under metoden LoadModel är bra:

    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)}%"));
    }
    

    Den här koden skapar en GameObject som fungerar som överordnad till testmodellen. Sedan anropas LoadModel-metoden för att läsa in modellen "builtin://Engine", som är en tillgång som är inbyggd i Azure Remote Rendering i syfte att testa renderingen.

  2. Spara koden.

  3. Tryck på knappen Spela upp i Unity-redigeraren för att starta processen med att ansluta till Azure Remote Rendering och skapa en ny session.

  4. Du ser inte mycket i spelvyn, men konsolen visar tillståndet för programmet som ändras. Det kommer sannolikt att gå vidare till ConnectingToNewRemoteSession, och stanna där, eventuellt i upp till fem minuter.

  5. Välj RemoteRenderingCoordinator GameObject för att se dess anslutna skript i inspektören. Titta på uppdateringen av tjänstkomponenten när den fortsätter genom sina initierings- och anslutningssteg.

  6. Övervaka konsolens utdata – väntar på att tillståndet ska ändras till Runtime Anslut ed.

  7. När körningen är ansluten högerklickar du på RemoteRenderingCoordinator i inspektören för att exponera snabbmenyn. Välj sedan alternativet Load Test Model (Läs in testmodell ) på snabbmenyn, som läggs till i den del av [ContextMenu("Load Test Model")] koden ovan.

    Skärmbild av Unity-inspektören för skriptet för fjärrrenderingskoordinator. Markerar instruerar att först högerklicka på namnlisten och sedan välja Läs in testmodell på snabbmenyn.

  8. Titta på konsolen för utdata från ProgressHandler som vi skickade till metoden LoadModel.

  9. Se den fjärranslutna modellen!

Kommentar

Fjärrmodellen visas aldrig i scenvyn, endast i spelvyn. Detta beror på att ARR återger bildrutorna på distans specifikt för perspektivet för spelvisningskameran och inte känner till redigeringskameran (används för att återge scenvyn).

Nästa steg

Skärmbild av Unity som kör projektet i uppspelningsläge. En bilmotor återges i mitten av visningsporten.

Grattis! Du har skapat ett grundläggande program som kan visa fjärrrenderade modeller med hjälp av Azure Remote Rendering. I nästa självstudie kommer vi att integrera MRTK och importera våra egna modeller.