Bagikan melalui


Tutorial: Menampilkan model yang dirender dari jarak jauh

Dalam tutorial ini, Anda akan mempelajari cara:

  • Provisikan instans Azure Remote Rendering (ARR)
  • Buat dan hentikan sesi penyajian
  • Gunakan kembali sesi penyajian yang sudah ada
  • Sambungkan dan putuskan sambungan dari sesi
  • Muat model ke dalam sesi penyajian

Prasyarat

Untuk tutorial ini, Anda perlu:

  • Langganan Azure berbayar sesuai waktu aktif Buat akun
  • Windows SDK 10.0.18362.0 (unduh)
  • Versi terbaru Visual Studio 2022 (unduh)
  • Git (unduh)
  • Plugin Git LFS (unduh)
  • Unity (melihat persyaratan sistem untuk versi yang didukung)
  • Pengetahuan menengah tentang Unity dan bahasa C# (misalnya: membuat skrip dan objek, menggunakan prefab, mengonfigurasi peristiwa Unity, dll.)

Provisikan instans Azure Remote Rendering (ARR)

Untuk mendapatkan akses ke layanan Azure Remote Rendering, Anda harus membuat akun terlebih dahulu.

Membuat proyek Unity baru

Tip

Repositori sampel ARR yang berisi proyek dengan semua tutorial sudah selesai, dapat digunakan sebagai referensi. Lihat di Unity\Tutorial-Complete untuk proyek Unity lengkap.

Dari Unity Hub, buat proyek baru. Dalam contoh ini, kami berasumsi proyek sedang dibuat dalam folder bernama RemoteRendering.

Cuplikan layar Unity Hub memperlihatkan dialog Buat Proyek Unity Baru. Panel 3D dipilih.

Sertakan paket Azure Remote Rendering dan OpenXR

Ikuti instruksi tentang cara menambahkan paket Azure Remote Rendering dan OpenXR ke Proyek Unity Anda.

Catatan

Jika Unity menampilkan dialog peringatan setelah mengimpor paket OpenXR yang menanyakan apakah akan mengaktifkan backend platform asli untuk sistem input baru, klik Tidak untuk saat ini. Anda akan mengaktifkannya di langkah selanjutnya.

Konfigurasikan kamera

  1. Pilih simpul Kamera Utama.

  2. Buka menu konteks dengan mengklik kanan komponen Transformasi dan pilih opsi Reset :

    Cuplikan layar inspektur Unity untuk komponen Transformasi. Menu konteks dibuka dan Reset dipilih.

  3. Atur Hapus bendera ke Warna Solid

  4. Atur Latar Belakang ke Hitam (#000000), dengan alfa (A) transparan sepenuhnya (0)

    Cuplikan layar dialog roda Warna Unity. Warna diatur ke 0 untuk semua komponen R G B A.

  5. Atur Clipping Planes ke Near = 0.1 dan Far = 20. Penyiapan ini berarti merender geometri klip yang lebih dekat dari 10 cm atau lebih jauh dari 20 meter.

    Cuplikan layar inspektur Unity untuk komponen Kamera.

Sesuaikan pengaturan proyek

  1. Buka Edit > Pengaturan Proyek...

  2. Pilih Kualitas dari menu daftar kiri

    1. Ubah Tingkat Kualitas Default semua platform menjadi Rendah. Pengaturan ini memungkinkan penyajian konten lokal yang lebih efisien dan tidak memengaruhi kualitas konten yang dirender dari jarak jauh.

      Cuplikan layar dialog Pengaturan Proyek Unity. Entri Kualitas dipilih dalam daftar di sebelah kiri. Menu konteks untuk tingkat kualitas default dibuka di sebelah kanan. Entri rendah dipilih.

    Catatan

    Dalam cakupan tutorial ini, kita tetap dengan alur render bawaan Unity. Jika Anda ingin menggunakan Universal Render Pipeline, lihat Alur Render Unity untuk langkah-langkah penyiapan tambahan.

  3. Pilih Manajemen Plugin XR dari menu daftar kiri

    1. Klik tombol Instal Manajemen Plugin XR.
    2. Pilih tab pengaturan Universal Windows Platform, yang dinyatakan sebagai ikon Windows.
    3. Pilih kotak centang Buka XR di bawah Penyedia Plug-In
    4. Jika dialog terbuka yang meminta Anda untuk mengaktifkan backend platform asli untuk sistem input baru, pilih Tidak.

    Cuplikan layar dialog Pengaturan Proyek Unity. Entri Manajemen Plug-in XR dipilih dalam daftar di sebelah kiri. Tab dengan logo jendela disorot di sebelah kanan. Kotak centang Buka XR di bawah ini juga disorot.

    Catatan

    Jika grup fitur Microsoft HoloLens dinonaktifkan, Plugin Windows Mixed Reality OpenXR hilang dari proyek Anda. Ikuti instruksi tentang cara menambahkan paket Azure Remote Rendering dan OpenXR untuk menginstalnya.

  4. Pilih OpenXR dari menu daftar kiri

    1. Atur Mode Pengiriman Kedalaman ke Kedalaman 16 Bit
    2. Tambahkan Profil Interaksi Tangan Microsoft ke Profil Interaksi.
    3. Aktifkan fitur OpenXR ini:
      • Azure Remote Rendering
      • Pelacakan Tangan
      • Fitur Mixed Reality
      • Model Pengontrol Gerak

    Cuplikan layar dialog Pengaturan Proyek Unity. Subentry Open XR dipilih dalam daftar di sebelah kiri. Sorotan di sisi kanan ditempatkan pada pengaturan fitur Mode Pengiriman Kedalaman, Profil Interaksi, dan Buka XR.

    Catatan

    Jika Anda tidak melihat fitur OpenXR yang diperlukan yang tercantum Plugin OpenXR Windows Mixed Reality hilang dari proyek Anda. Ikuti instruksi tentang cara menambahkan paket Azure Remote Rendering dan OpenXR untuk menginstalnya.

  5. Pilih Pemutar dari menu daftar kiri

    1. Pilih tab pengaturan Universal Windows Platform, yang dinyatakan sebagai ikon Windows.
    2. Perluas Pengaturan Lain
    3. Di bawah Penyajian ubah Ruang Warna menjadi Linier dan mulai ulang Unity saat meminta Anda.
    4. Di bawah Konfigurasi ubah Penanganan Input Aktif ke Unity dan mulai ulang Unity saat meminta Anda. Cuplikan layar dialog Pengaturan Proyek Unity. Entri Pemutar dipilih dalam daftar di sebelah kiri. Sorotan di sisi kanan ditempatkan pada tab dengan logo Windows, pengaturan Ruang Warna, dan pengaturan Penanganan input aktif.
    5. Perluas Pengaturan Penerbitan
    6. Gulir ke bawah ke Kemampuan dan pilih:
      • InternetClient
      • InternetClientServer
      • Persepsi Spasial
      • PrivateNetworkClientServer(opsional). Pilih opsi ini jika Anda ingin menyambungkan Unity remote debugger ke perangkat Anda.
    7. Di bawah Keluarga Perangkat yang Didukung, aktifkanHolografik dan DesktopCuplikan layar dialog Pengaturan Proyek Unity. Entri Pemutar dipilih dalam daftar di sebelah kiri. Sorotan di sisi kanan ditempatkan pada pengaturan Kemampuan dan Keluarga Perangkat yang Didukung.
  6. Tutup atau tambatkan panel Pengaturan Proyek

  7. Buka Pengaturan File-Build>

    1. Pilih Platform Windows Universal
    2. Konfigurasikan setelan Anda agar sesuai dengan yang ditemukan di bawah ini
    3. Tekan tombol Beralih Platform .
      Cuplikan layar dialog Unity Build Pengaturan. Entri Platform Windows Universal dipilih dalam daftar di sebelah kiri. Sorotan di sisi kanan ditempatkan pada kotak dropdown pengaturan dan tombol Beralih Platform.
  8. Setelah Unity mengubah platform, tutup panel build.

Validasi penyetelan proyek

Lakukan langkah-langkah berikut untuk memvalidasi bahwa pengaturan proyek sudah benar.

  1. Pilih entri ValidateProject dari menu RemoteRendering di toolbar editor Unity.

  2. Tinjau jendela Validator Proyek untuk kesalahan dan perbaiki pengaturan proyek jika perlu.

    Cuplikan layar dialog Validator Proyek Unity. Dialog menunjukkan daftar aturan yang diperlukan, direkomendasikan, dan pengembangan yang semuanya berhasil diperiksa.

Catatan

Jika Anda menggunakan MRTK dalam proyek dan mengaktifkan subsistem kamera, MRTK akan mengambil alih perubahan manual yang Anda terapkan ke kamera. Ini termasuk perbaikan dari alat ValidateProject.

Buat skrip untuk mengoordinasikan koneksi dan status Azure Remote Rendering

Ada empat tahap dasar untuk menampilkan model yang dirender dari jarak jauh, yang diuraikan dalam bagan alur di bawah ini. Setiap tahap harus dilakukan secara berkinerja. Langkah selanjutnya adalah membuat skrip yang mengelola status aplikasi dan melanjutkan setiap tahap yang diperlukan.

Diagram empat tahap yang diperlukan untuk memuat model.

  1. Di panel Proyek, di bawah Aset, buat folder baru yang disebut RemoteRenderingCore. Kemudian di dalam RemoteRenderingCore, buat folder lain yang disebut Scripts.

  2. Buat skrip C# baru yang disebut RemoteRenderingCoordinator. Proyek Anda akan terlihat seperti ini:

    Cuplikan layar hierarki Unity Project yang berisi skrip baru.

    Skrip koordinator ini melacak dan mengelola status penyajian jarak jauh. Sebagai catatan, beberapa kode ini digunakan untuk mempertahankan status, mengekspos fungsionalitas ke komponen lain, memicu peristiwa, dan menyimpan data khusus aplikasi yang tidak terkait langsung dengan Azure Remote Rendering. Gunakan kode di bawah ini sebagai titik awal, dan kami akan membahas dan mengimplementasikan kode Azure Remote Rendering tertentu nanti dalam tutorial.

  3. Buka RemoteRenderingCoordinator di editor kode Anda dan ganti seluruh kontennya dengan kode di bawah ini:

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

Buat Azure Remote Rendering GameObject

Koordinator penyajian jarak jauh dan skrip yang diperlukan (ARRServiceUnity) adalah MonoBehaviours yang harus dilampirkan ke GameObject di tempat kejadian. Skrip ARRServiceUnity disediakan oleh ARR untuk mengekspos banyak fungsi ARR untuk menghubungkan dan mengelola sesi jarak jauh.

  1. Buat GameObject baru di adegan (Ctrl+Shift+N atau GameObject-Create> Empty) dan beri nama RemoteRenderingCoordinator.
  2. Tambahkan skrip RemoteRenderingCoordinator ke RemoteRenderingCoordinator GameObject.
    Cuplikan layar dialog Unity Add Component. Bidang teks pencarian berisi teks RemoteRenderingCoordinator.
  3. Konfirmasi skrip ARRServiceUnity, yang muncul sebagai Layanan di inspektur, secara otomatis ditambahkan ke GameObject. Jika Anda bertanya-tanya, ini adalah hasil yang ada [RequireComponent(typeof(ARRServiceUnity))] di bagian atas skrip RemoteRenderingCoordinator.
  4. Tambahkan kredensial Azure Remote Rendering, Domain Akun Anda, dan Domain Remote Rendering ke skrip koordinator:
    Cuplikan layar inspektur Unity dari Skrip Koordinator Remote Rendering. Bidang input info masuk disorot.

Inisiasikan Penyajian Azure Remote Rendering

Sekarang setelah kita memiliki kerangka kerja untuk koordinator kita, kita akan mengimplementasikan masing-masing dari empat tahap yang dimulai dengan Inisialisasi Remote Rendering.

Diagram empat tahap yang diperlukan untuk memuat model. Tahap pertama

Inisiasi memberi tahu Azure Remote Rendering objek kamera mana yang digunakan untuk menyajikan dan mengembangkan mesin status menjadi NotAuthorized. Status ini berarti diinisialisasi tetapi belum berwenang untuk menyambungkan ke sesi. Karena memulai sesi ARR dikenakan biaya, kami perlu mengonfirmasi bahwa pengguna ingin melanjutkan.

Ketika memasuki status NotAuthorized, CheckAuthorization disebut, yang memanggil peristiwa RequestingAuthorization dan menentukan informasi masuk akun mana yang akan digunakan (AccountInfo didefinisikan di dekat bagian atas kelas dan menggunakan informasi masuk yang Anda tentukan melalui Unity Inspector pada langkah di atas).

Catatan

Kompilasi ulang runtime tidak didukung oleh ARR. Memodifikasi skrip dan menyimpannya saat mode pemutaran aktif dapat mengakibatkan Unity membeku dan harus mematikan paksa melalui task manager. Selalu pastikan Anda telah menghentikan mode putar sebelum mengedit skrip.

  1. Ganti kontenInitializeARR dan InitializeSessionService dengan kode lengkap di bawah ini:

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

Untuk maju dari NotAuthorized ke NoSession, kami biasanya akan menyajikan dialog modal kepada pengguna sehingga mereka dapat memilih (dan kami melakukan hal itu di bab lain). Untuk saat ini, kami secara otomatis melewati pemeriksaan otorisasi dengan memanggil ByPassAuthentication segera setelah peristiwa RequestingAuthorization dipicu.

  1. Pilih RemoteRenderingCoordinator GameObject dan temukan OnRequestingAuthorization Unity Event yang terekspos di inspektur komponen RemoteRenderingCoordinator.

  2. Tambahkan peristiwa baru dengan menekan '+' di kanan bawah.

  3. Seret komponen ke peristiwanya sendiri, untuk mereferensikan dirinya sendiri. Cuplikan layar inspektur Unity dari Skrip Koordinator Remote Rendering. Bilah judul komponen disorot dan panah menyambungkannya ke peristiwa Otorisasi Saat Diminta.

  4. Di menu drop-down, pilih RemoteRenderingCoordinator -> BypassAuthorization.
    Cuplikan layar peristiwa Otorisasi Saat Diminta.

Buat atau gabung dengan sesi jarak jauh

Tahap kedua adalah Membuat atau Menggabungkan Sesi Penyajian Jarak Jauh (untuk informasi selengkapnya tentang sesi penyajian, lihat Sesi Penyajian Jarak Jauh).

Diagram empat tahap yang diperlukan untuk memuat model. Tahap kedua

Sesi jarak jauh adalah lokasi penyajian model. Metode JoinRemoteSession( ) mencoba bergabung dengan sesi yang ada, dilacak dengan properti LastUsedSessionID atau jika ada ID sesi aktif yang ditetapkan pada SessionIDOverride. SessionIDOverride hanya ditujukan untuk debugging, itu hanya boleh digunakan ketika Anda tahu sesi itu ada dan ingin secara eksplisit terhubung ke sana.

Jika tidak ada sesi yang tersedia, sesi baru akan dibuat. Namun, membuat sesi baru adalah operasi yang memakan waktu. Oleh karena itu, Anda harus mencoba membuat sesi hanya jika diperlukan dan menggunakannya kembali jika memungkinkan (lihat Siap Komersial: Kumpulan sesi, penjadwalan, dan praktik terbaik untuk informasi lebih lanjut tentang mengelola sesi).

Tip

StopRemoteSession() akan mengakhiri sesi aktif. Untuk mencegah biaya yang tidak perlu, Anda harus selalu menghentikan sesi ketika mereka tidak lagi diperlukan.

Mesin status sekarang akan maju ke ConnectingToNewRemoteSession atau ConnectingToExistingRemoteSession, tergantung pada sesi yang tersedia. Keduanya membuka sesi yang ada atau membuat sesi baru memicu peristiwa ARRSessionService.OnSessionStatusChanged, menjalankan metode OnRemoteSessionStatusChanged kami. Idealnya, ini menghasilkan memajukan komputer status ke RemoteSessionReady.

  1. Untuk bergabung dengan sesi baru, ubah kode untuk mengganti metode JoinRemoteSession( ) dan StopRemoteSession( ) dengan contoh yang diselesaikan di bawah ini:
/// <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();
    }
}

Jika Anda ingin menghemat waktu dengan menggunakan kembali sesi, pastikan untuk menonaktifkan opsi Hentikan Otomatis Sesi di komponen ARRServiceUnity. Perlu diingat bahwa ini akan membuat sesi berjalan, bahkan ketika tidak ada yang terhubung dengan mereka. Sesi Anda dapat berjalan selama MaxLeaseTime belum dimatikan oleh server (Nilai untuk MaxLeaseTime dapat dimodifikasi di Koordinator Azure Remote Rendering, di bawah Default Sesi Baru). Di sisi lain, jika Anda secara otomatis mematikan setiap sesi saat memutuskan sambungan, Anda harus menunggu sesi baru dimulai setiap saat, yang bisa menjadi proses yang panjang.

Catatan

Menghentikan sesi akan berlaku segera dan tidak dapat dibatalkan. Setelah berhenti, Anda harus membuat sesi baru, dengan overhead startup yang sama.

Sambungkan runtime bahasa umum lokal ke sesi jarak jauh

Selanjutnya, aplikasi perlu menghubungkan runtime bahasa umum lokalnya ke sesi jarak jauh.

Diagram empat tahap yang diperlukan untuk memuat model. Tahap ketiga

Aplikasi ini juga perlu mendengarkan acara tentang koneksi antara runtime bahasa umum dan sesi saat ini; perubahan status tersebut ditangani dalam OnLocalRuntimeStatusChanged. Kode ini memajukan status kita ke Koneksi ingToRuntime. Setelah tersambung di OnLocalRuntimeStatusChanged, status maju ke Runtime Koneksi ed. Menghubungkan ke runtime bahasa umum adalah status terakhir yang menjadi perhatian koordinator itu sendiri, yang berarti aplikasi dilakukan dengan semua konfigurasi umum dan siap untuk memulai pekerjaan spesifik sesi memuat dan merender model.

  1. Ganti metode ConnectRuntimeToRemoteSession( ) dan DisconnectRuntimeFromRemoteSession() dengan versi lengkap di bawah ini.
  2. Penting untuk mencatat metode Unity LateUpdate dan memperbarui sesi aktif saat ini. Ini memungkinkan sesi saat ini untuk mengirim/menerima pesan dan memperbarui buffer bingkai dengan bingkai yang diterima dari sesi jarak jauh. Sangat penting bagi ARR berfungsi dengan benar.
/// <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;
}

Catatan

Menyambungkan runtime bahasa umum lokal ke sesi jarak jauh bergantung pada Pembaruan yang dipanggil pada sesi yang saat ini aktif. Jika merasa aplikasi Anda tidak pernah mengalami kemajuan melewati status ConnectingToRuntime, pastikan Anda memanggil Pembaruan secara teratur pada sesi aktif.

Memuat model

Dengan fondasi yang diperlukan, Anda siap untuk memuat model ke dalam sesi jarak jauh dan mulai menerima bingkai.

Diagram empat tahap yang diperlukan untuk memuat model. Tahap keempat

Metode LoadModel dirancang untuk menerima jalur model, progress handler, dan transformasi induk. Argumen ini digunakan untuk memuat model ke sesi jarak jauh, memperbarui pengguna pada kemajuan pemuatan, dan mengorientasikan model yang dirender dari jarak jauh berdasarkan transformasi induk.

  1. Ganti metode LoadModel sepenuhnya dengan kode di bawah ini:

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

Kode di atas melakukan langkah-langkah berikut:

  1. Buat Entitas Jarak Jauh.
  2. Buat GameObject lokal untuk mewakili entitas jarak jauh.
  3. Konfigurasikan GameObject lokal untuk menyinkronkan statusnya (yaitu Transformasi) ke entitas jarak jauh setiap bingkai.
  4. Muat data model dari Azure Blob Storage ke entitas jarak jauh.
  5. Kembalikan Entitas induk untuk referensi nanti.

Tampilkan model pengujian

Kami sekarang memiliki semua kode yang diperlukan untuk melihat model yang dirender dari jarak jauh, keempat tahap yang diperlukan untuk penyajian jarak jauh selesai. Sekarang kita perlu menambahkan sedikit kode untuk memulai proses beban model.

Diagram empat tahap yang diperlukan untuk memuat model. Semua tahapan ditandai sebagai selesai.

  1. Menambahkan kode berikut ke kelas RemoteRenderingCoordinator, tepat di bawah metode LoadModel tidak masalah:

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

    Kode ini membuat GameObject untuk bertindak sebagai induk model pengujian. Kemudian memanggil metode LoadModel untuk memuat model "builtin://Engine", yang merupakan aset yang dibangun ke dalam Azure Remote Rendering untuk tujuan pengujian penyajian.

  2. Simpan kode Anda.

  3. Tekan tombol Putar di Editor Unity untuk memulai proses menyambungkan ke Azure Remote Rendering dan membuat sesi baru.

  4. Namun, Anda tidak akan melihat banyak dalam tampilan Game, Konsol menunjukkan status perubahan aplikasi. Kemungkinan akan maju ke ConnectingToNewRemoteSession, dan tetap di sana, mungkin hingga lima menit.

  5. Pilih RemoteRenderingCoordinator GameObject untuk melihat skrip terlampirnya di inspektur. Tonton pembaruan komponenLayanan karena pembaruannya berlangsung melalui langkah-langkah inisiasi dan koneksinya.

  6. Pantau output Konsol - menunggu status berubah menjadi RuntimeConnected.

  7. Setelah runtime terhubung, klik kanan pada RemoteRenderingCoordinator di inspektur untuk mengekspos menu konteks. Kemudian, pilih opsi Muat Model Uji di menu konteks, ditambahkan oleh [ContextMenu("Load Test Model")] bagian dari kode kami di atas.

    Cuplikan layar inspektur Unity dari Skrip Koordinator Remote Rendering. Sorotan menginstruksikan untuk terlebih dahulu mengklik kanan pada bilah judul lalu pilih Muat Model Uji dari menu konteks.

  8. Tonton Konsol untuk output ProgressHandler yang kami lewati ke metode LoadModel.

  9. Lihat model yang dirender dari jarak jauh!

Catatan

Model jarak jauh tidak akan pernah terlihat dalam tampilan Scene, hanya dalam tampilan game. Ini karena ARR menyajikan bingkai dari jarak jauh khusus untuk perspektif kamera tampilan Game dan tidak mengetahui kamera Editor (digunakan untuk menyajikan tampilan Scene).

Langkah berikutnya

Cuplikan layar Unity yang menjalankan proyek dalam mode Putar. Mesin mobil dirender di tengah viewport.

Selamat! Anda telah membuat aplikasi dasar yang mampu menampilkan model yang dirender dari jarak jauh menggunakan Azure Remote Rendering. Dalam tutorial berikutnya, kita akan mengintegrasikan MRTK dan mengimpor model kita sendiri.