Share via


Zelfstudie: Een extern gerenderd model weergeven

In deze zelfstudie leert u het volgende:

  • Een instantie van Azure Remote Rendering (ARR) inrichten
  • Een rendering-sessie maken en stoppen
  • Een bestaande rendering-sessie opnieuw gebruiken
  • Verbinding maken en de verbinding verbreken met sessies
  • Modellen laden in een rendering-sessie

Vereisten

Voor deze zelfstudie hebt u het volgende nodig:

  • Een actief Azure-abonnement voor betalen naar gebruik Een account maken
  • Windows SDK 10.0.18362.0 (download)
  • De nieuwste versie van Visual Studio 2022 (download)
  • Git (downloaden)
  • Git LFS-invoegtoepassing (download)
  • Unity (zie systeemvereisten voor ondersteunde versies)
  • Basiskennis van Unity en de C# -taal (bijvoorbeeld: scripts en objecten maken, prefabs gebruiken, Unity-gebeurtenissen configureren enz.)

Een instantie van Azure Remote Rendering (ARR) inrichten

Als u toegang wilt krijgen tot de Azure Remote Rendering-service, moet u eerst een account maken.

Een nieuw Unity-project maken

Fooi

De opslagplaats voor ARR-voorbeelden bevat een project waarin alle zelfstudies voltooid zijn, u kunt dit gebruiken ter referentie. Kijk in Unity\Tutorial-Complete voor het voltooide Unity-project.

Maak vanuit de Unity-hub een nieuw project. In dit voorbeeld wordt ervan uitgegaan dat het project wordt gemaakt in een map met de naam RemoteRendering.

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

De Azure Remote Rendering- en OpenXR-pakketten opnemen

Volg de instructies voor het toevoegen van de Azure Remote Rendering- en OpenXR-pakketten aan uw Unity-project.

Notitie

Als Unity een waarschuwingsdialoogvenster weergeeft na het importeren van het OpenXR-pakket waarin wordt gevraagd of de systeemeigen platformback-ends voor het nieuwe invoersysteem moeten worden ingeschakeld, klikt u voorlopig op Nee . U schakelt deze in een latere stap in.

De camera configureren

  1. Selecteer het hoofdcamera-knooppunt.

  2. Open het contextmenu door met de rechtermuisknop op het onderdeel Transformeren te klikken en de optie Opnieuw instellen te selecteren:

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

  3. Stel Vlaggen wissen in op Effen kleur

  4. Stel Achtergrond in op Zwart (#000000), met volledig transparante (0) alfa (A)

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

  5. Stel knipvlakken in op Near = 0,1 en Far = 20. Deze instelling betekent dat de geometrie van clips dichter dan 10 cm of verder dan 20 meter wordt weergegeven.

    Screenshot of the Unity inspector for a Camera component.

De projectinstellingen aanpassen

  1. Project bewerken > openen Instellingen...

  2. Selecteer Kwaliteit in het lijstmenu links

    1. Wijzig het Standaardkwaliteitsniveau van alle platforms naar Laag. Deze instelling maakt efficiënter weergeven van lokale inhoud mogelijk en heeft geen invloed op de kwaliteit van extern gerenderde inhoud.

      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.

    Notitie

    In het bereik van deze zelfstudie houden we ons aan de ingebouwde Render-pijplijn van Unity. Als u de Universal Render Pipeline wilt gebruiken, raadpleegt u Unity Render Pipelines voor aanvullende installatiestappen.

  3. Selecteer XR Plugin Management in het linkerlijstmenu

    1. Klik op de knop XR Plugin Management installeren.
    2. Selecteer het tabblad Instellingen universeel Windows-platform, dat wordt weergegeven als een Windows-pictogram.
    3. Schakel het selectievakje XR openen in onder Invoegtoepassingsproviders
    4. Als er een dialoogvenster wordt geopend met de vraag om de systeemeigen platformback-ends voor het nieuwe invoersysteem in te schakelen, selecteert u Nee.

    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.

    Notitie

    Als de Microsoft HoloLens-functiegroep is uitgeschakeld, ontbreekt de Windows Mixed Reality OpenXR-invoegtoepassing in uw project. Volg de instructies voor het toevoegen van de Azure Remote Rendering- en OpenXR-pakketten om deze te installeren.

  4. OpenXR selecteren in het menu aan de linkerkant

    1. Diepteinzendingsmodus instellen op diepte 16-bits
    2. Voeg het Microsoft Hand Interaction-profiel toe aan interactieprofielen.
    3. Schakel deze OpenXR-functies in:
      • Azure Remote Rendering
      • Handtracering
      • Mixed Reality-functies
      • Bewegingscontrollermodel

    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.

    Notitie

    Als de vereiste OpenXR-functies niet worden weergegeven, ontbreekt de Windows Mixed Reality OpenXR-invoegtoepassing in uw project. Volg de instructies voor het toevoegen van de Azure Remote Rendering- en OpenXR-pakketten om deze te installeren.

  5. Selecteer Speler in het lijstmenu links

    1. Selecteer het tabblad Instellingen universeel Windows-platform, dat wordt weergegeven als een Windows-pictogram.
    2. Andere Instellingen uitvouwen
    3. Wijzig onder Rendering de kleurruimte in Lineair en start Unity opnieuw op wanneer u hier om wordt gevraagd.
    4. Wijzig onder Configuratie Active Input Handling in Zowel en start Unity opnieuw op wanneer u hier om wordt gevraagd. 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. Publicatie Instellingen uitvouwen
    6. Schuif omlaag naar Mogelijkheden en selecteer:
      • InternetClient
      • InternetClientServer
      • SpatialPerception
      • PrivateNetworkClientServer (optioneel). Selecteer deze optie als u de Unity-foutopsporing met uw apparaat wilt verbinden.
    7. Schakel onder Ondersteunde apparaten, Holographic en 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. in
  6. Sluit of zet het paneel Projectinstellingen

  7. Open file-build Instellingen>

    1. Selecteer Universeel Windows-platform
    2. Configureer uw instellingen zodat deze overeenkomen met die hieronder
    3. Druk op de knop Switch Platform .
      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. Nadat Unity het platform heeft veranderd, sluit u het build-deelvenster.

Projectinstellingen valideren

Voer de volgende stappen uit om te controleren of de projectinstellingen juist zijn.

  1. Kies de vermelding ValidateProject in het menu RemoteRendering in de werkbalk van de Unity-editor.

  2. Controleer waar nodig het venster Project Validator op fouten en los projectinstellingen op.

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

Notitie

Als u MRTK in uw project gebruikt en het camerasubsysteem inschakelt, overschrijft MRTK handmatige wijzigingen die u op de camera toepast. Dit omvat oplossingen van het hulpprogramma ValidateProject.

Een script maken om de verbinding en status van Azure Remote Rendering te coördineren

Er zijn vier basisfasen voor het weergeven van extern gegenereerde modellen, zoals te zien is in het onderstaande stroomdiagram. Elke fase moet in de aangegeven volgorde worden uitgevoerd. De volgende stap is het maken van een script waarmee de toepassingsstatus wordt beheerd en elke vereiste fase wordt doorlopen.

Diagram of the four stages required to load a model.

  1. Maak in het deelvenster Project onder Assetseen nieuwe map met de naam RemoteRenderingCore. Maak vervolgens in RemoteRenderingCore een andere map met de naam Scripts.

  2. Maak een nieuw C#-script met de naam RemoteRenderingCoordinator. Uw project moet er als volgt uitzien:

    Screenshot of Unity Project hierarchy containing the new script.

    Met dit coördinatorscript wordt de status van externe rendering bijgehouden en beheerd. Opmerking: sommige van deze code worden gebruikt voor het onderhouden van de status, het blootstellen van functionaliteit aan andere onderdelen, het activeren van gebeurtenissen en het opslaan van toepassingsspecifieke gegevens die niet rechtstreeks zijn gerelateerd aan Azure Remote Rendering. Gebruik de onderstaande code als uitgangspunt. We bespreken en implementeren de specifieke code van Azure Remote Rendering verderop in de zelfstudie.

  3. Open RemoteRenderingCoordinator in uw code-editor en vervang de volledige inhoud door de onderstaande code:

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

Het GameObject voor Azure Remote Rendering maken

De remote rendering-coördinator en het vereiste script (ARRServiceUnity) zijn beide MonoBehaviours die gekoppeld moeten worden aan een GameObject in de scène. Het ARRServiceUnity-script wordt door ARR verschaft om een groot deel van de ARR-functionaliteit beschikbaar te maken om verbinding te maken met externe sessies en ze te beheren.

  1. Maak een nieuw GameObject in de scène (Ctrl+Shift+N of GameObject-Create> Empty) en geef deze de naam RemoteRenderingCoordinator.
  2. Voeg het script RemoteRenderingCoordinator toe aan het RemoteRenderingCoordinator GameObject.
    Screenshot of the Unity Add Component dialog. The search text field contains the text RemoteRenderingCoordinator.
  3. Controleer of het ARRServiceUnity-script, dat wordt weergegeven als Service in de Inspector, automatisch wordt toegevoegd aan het GameObject. Ter informatie, dit is een resultaat dat [RequireComponent(typeof(ARRServiceUnity))] heeft bovenaan het RemoteRenderingCoordinator-script.
  4. Voeg uw Azure Remote Rendering-referenties, uw accountdomein en het Remote Rendering-domein toe aan het coördinatorscript:
    Screenshot of the Unity inspector of the Remote Rendering Coordinator Script. The credential input fields are highlighted.

Azure Remote Rendering initialiseren

Nu we het framework voor onze coördinator hebben, implementeren we elk van de vier fasen die beginnen met Initialize Remote Rendering.

Diagram of the four stages required to load a model. The first stage

Initialiseren vertelt Azure Remote Rendering welk camera-object moet worden gebruikt voor rendering en werkt de statusmachine bij naar NotAuthorized. Deze status betekent dat deze is geïnitialiseerd, maar nog niet gemachtigd is om verbinding te maken met een sessie. Aangezien een ARR-sessie beginnen kosten met zich meebrengt, moeten we bevestigen dat de gebruiker wilt doorgaan.

Wanneer de status NotAuthorized van toepassing is, wordt CheckAuthorization aangeroepen, wat vervolgens de gebeurtenis RequestingAuthorization aanroept en bepaalt welke accountreferenties gebruikt moeten worden (AccountInfo wordt opgegeven bovenaan de klasse en gebruikt de referenties die u hebt opgegeven in de Unity Inspector in de bovenstaande stap).

Notitie

Hercompilatie van runtime wordt niet ondersteund door ARR. Als u het script wijzigt en opslaat terwijl de afspeelmodus actief is, kan dit ertoe leiden dat Unity vastloopt en u dit moet afsluiten in Taakbeheer. Zorg er altijd voor dat u de afspeelmodus hebt gestopt voor u uw scripts bewerkt.

  1. Vervang de inhoud van InitializeARR en InitializeSessionService door de voltooide code hieronder:

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

Om verder te gaan van NotAuthorized naar NoSession, presenteren we doorgaans een modaal dialoogvenster aan de gebruiker, zodat ze kunnen kiezen (en dat doen we in een ander hoofdstuk). Voorlopig wordt de autorisatiecontrole automatisch overgeslagen door ByPassAuthentication aan te roepen zodra de requestingAuthorization-gebeurtenis wordt geactiveerd.

  1. Selecteer het GameObject RemoteRenderingCoordinator en zoek de Unity-gebeurtenis OnRequestingAuthorization in de Inspector van de component RemoteRenderingCoordinator.

  2. Voeg een nieuwe gebeurtenis toe door op de '+' te drukken links onderaan.

  3. Sleep het onderdeel naar een eigen gebeurtenis om naar zichzelf te verwijzen. 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. Selecteer RemoteRenderingCoordinator -> BypassAuthorization in de vervolgkeuzelijst.
    Screenshot of the On Requesting Authorization event.

Een externe sessie maken of eraan deelnemen

De tweede fase is het maken of deelnemen aan een Remote Rendering-sessie (zie Remote Rendering-sessies voor meer informatie over renderingsessies).

Diagram of the four stages required to load a model. The second stage

De externe sessie is de plaats waar de modellen worden gegenereerd. De methode JoinRemoteSession( ) probeert deel te nemen aan een bestaande sessie, bijgehouden met de eigenschap LastUsedSessionID of als er een toegewezen actieve sessie-id is op SessionIDOverride. SessionIDOverride dient enkel voor foutopsporing, en mag enkel gebruikt worden wanneer u weet dat de sessie bestaat en u er expliciet verbinding mee wilt maken.

Als er geen sessies beschikbaar zijn, wordt er een nieuwe sessie gemaakt. Een nieuwe sessie maken is echter een tijdrovende bewerking. Probeer daarom alleen sessies te maken wanneer dat nodig is en gebruik ze waar mogelijk opnieuw (zie Commercial Ready: Session pooling, planning en best practices voor meer informatie over het beheren van sessies).

Fooi

StopRemoteSession() maakt een einde aan de actieve sessie. Als u onnodige kosten wilt voorkomen, moet u sessies altijd stopzetten wanneer ze niet meer nodig zijn.

De toestandsmachine gaat nu verder naar ConnectingToNewRemoteSession of ConnectingToExistingRemoteSession, afhankelijk van de beschikbare sessies. Zowel het openen van een bestaande sessie als het maken van een nieuwe sessie activeert de gebeurtenis ARRSessionService.OnSessionStatusChanged , waarbij de methode OnRemoteSessionStatusChanged wordt uitgevoerd. Idealiter leidt dit ertoe dat de statusmachine naar RemoteSessionReady gaat.

  1. Als u wilt deelnemen aan een nieuwe sessie, wijzig dan de code om de methodes JoinRemoteSession( ) en StopRemoteSession( ) te vervangen door de voltooide voorbeelden:
/// <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();
    }
}

Als u tijd wilt besparen door sessies opnieuw te gebruiken, deactiveer dan de optie Sessie automatisch stoppen in de component ARRServiceUnity. Houd er rekening mee dat er op deze manier sessies actief blijven, zelfs wanneer niemand ermee verbonden is. Uw sessie kan actief blijven zolang als uw MaxLeaseTime voordat deze wordt afgesloten door de server (de waarde voor MaxLeaseTime kan worden gewijzigd in de Remote Rendering Coordinator, onder Standaardwaarden voor nieuwe sessie). Als u daarentegen elke sessie automatisch afsluit wanneer de verbinding wordt verbroken, moet u elke keer wachten totdat een nieuwe sessie wordt gestart. Dit kan een langdurig proces zijn.

Notitie

Het stoppen van een sessie heeft direct effect en kan niet ongedaan worden gemaakt. Nadat de functie is gestopt, moet u een nieuwe sessie maken, met dezelfde opstart-overhead.

De lokale runtime verbinden met de externe sessie

Vervolgens moet de toepassing de lokale runtime verbinden met de externe sessie.

Diagram of the four stages required to load a model. The third stage

De toepassing moet ook luisteren naar gebeurtenissen over de verbinding tussen de runtime en de huidige sessie. Deze statuswijzigingen worden verwerkt in OnLocalRuntimeStatusChanged. Deze code verwijst naar Verbinding maken ToRuntime. Zodra de status is verbonden in OnLocalRuntimeStatusChanged, wordt de status verplaatst naar Runtime Verbinding maken ed. Verbinding maken met de runtime is de laatste status die de coördinator voor zijn rekening neemt, wat betekent dat de toepassing klaar is met alle algemene configuraties en kan beginnen met het sessiespecifieke werk van het laden en renderen van modellen.

  1. Vervang de methodes ConnectRuntimeToRemoteSession( ) en DisconnectRuntimeFromRemoteSession( ) door de voltooide versies hieronder.
  2. Het is belangrijk dat u rekening houdt met de Unity-methode LateUpdate en dat de huidige actieve sessie wordt bijgewerkt. Hierdoor kan de huidige sessie berichten verzenden/ontvangen en de framebuffer bijwerken met de frames die ontvangen worden via de externe sessie. Dat is essentieel voor de goede werking van ARR.
/// <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;
}

Notitie

De lokale runtime verbinden met een externe sessie is afhankelijk van het aanroepen van Bijwerken in de huidige actieve sessie. Als u merkt dat uw toepassing nooit verder raakt dan de status ConnectingToRuntime, zorg er dan voor dat u Bijwerken regelmatig aanroept in de actieve sessie.

Een model laden

Nu de vereiste basis is ingesteld, bent u klaar om een model in de externe sessie te laden en frames te ontvangen.

Diagram of the four stages required to load a model. The fourth stage

De methode LoadModel is ontworpen om een modelpad, voortgangshandler en bovenliggende transformatie te accepteren. Deze argumenten worden gebruikt om een model in de externe sessie te laden, de gebruiker bij te werken op de voortgang van het laden en het extern gerenderde model te richten op basis van de bovenliggende transformatie.

  1. Vervang de methode LoadModel volledig door de onderstaande code:

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

De bovenstaande code voert de volgende stappen uit:

  1. Maak een Externe entiteit.
  2. Maak een lokaal GameObject om de externe entiteit te vertegenwoordigen.
  3. Configureer het lokale GameObject om de status (dat wil gezegd, Transformeren) te synchroniseren met de externe entiteit elk frame.
  4. Laad modelgegevens van Blob Storage in de externe entiteit.
  5. Retourneer de bovenliggende Entiteit, voor later.

Het testmodel weergeven

We hebben nu alle code die vereist is om een extern gegenereerd model weer te geven. alle vier de vereiste fasen voor externe rendering zijn voltooid. Nu moeten we een beetje code toevoegen om het model te beginnen laden.

Diagram of the four stages required to load a model. All stages are marked as completed.

  1. Voeg de volgende code toe aan de RemoteRenderingCoordinator-klasse, net onder de LoadModel-methode bijvoorbeeld:

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

    Deze code maakt een GameObject dat dient als de bovenliggende entiteit voor het testmodel. Vervolgens roept het de methode LoadModel aan om het model 'builtin://Engine' te laden. Deze asset is ingebouwd in Azure Remote Rendering om de rendering te testen.

  2. Sla uw code op.

  3. Druk op de Afspeelknop in de Unity Editor om verbinding te maken met Azure Remote Rendering en een nieuwe sessie te maken.

  4. U ziet echter niet veel in de gameweergave, maar in de console wordt de status van de toepassing gewijzigd. Deze wordt wellicht bijgewerkt naar ConnectingToNewRemoteSession en blijft daar tot vijf minuten op staan.

  5. Selecteer het GameObject RemoteRenderingCoordinator om de bijgevoegde scripts te bekijken in de inspector. Kijk hoe de component Service wordt bijgewerkt terwijl deze de stappen voor initialisatie en verbinding doorloopt.

  6. Controleer de uitvoer van de Console, en wacht tot de status verandert naar RuntimeConnected.

  7. Zodra de runtime verbonden is, klikt u met de rechtermuisknop op de RemoteRenderingCoordinator in de inspector om het contextmenu weer te geven. Selecteer vervolgens de optie Testmodel laden in het contextmenu, toegevoegd door het [ContextMenu("Load Test Model")] gedeelte van de bovenstaande code.

    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. Controleer de Console op uitvoer van de ProgressHandler die we in de methode Loadmodel hebben ingevoerd.

  9. U ziet het extern gegenereerde model!

Notitie

Dit extern model zal nooit zichtbaar zijn in de Scèneweergave, enkel in de gameweergave. Dit komt doordat ARR de frames extern genereert, specifiek voor het perspectief van de camera voor Gameweergave. Het is zich niet bewust van de Editor-camera (die gebruikt wordt om de Scèneweergave te genereren).

Volgende stappen

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

Gefeliciteerd! U hebt een basistoepassing gemaakt waarmee extern gegenereerde modellen kunnen worden bekeken met behulp van Azure Remote Rendering. In de volgende zelfstudie integreren we MRTK en importeren we onze eigen modellen.