Partilhar via


Tutorial: Interfaces e modelos personalizados

Neste tutorial, irá aprender a:

  • Adicionar Kit de Ferramentas de Realidade Mista ao projeto
  • Gerenciar o estado do modelo
  • Configurar o Armazenamento de Blobs do Azure para ingestão de modelos
  • Carregar e processar modelos para renderização

Pré-requisitos

Introdução ao Kit de Ferramentas de Realidade Mista (MRTK)

O Mixed Reality Toolkit (MRTK) é um kit de ferramentas multiplataforma para a construção de experiências de realidade mista. Utilizamos o MRTK 2.8.3 pelas suas funcionalidades de interação e visualização.

O guia oficial para importar MRTK contém algumas etapas que não precisamos fazer. Apenas estes três passos são necessários:

  • Importando o 'Mixed Reality Toolkit/Mixed Reality Toolkit Foundation' versão 2.8.3 para o seu projeto através da Mixed Reality Feature Tool (Import MRTK).
  • Execute o assistente de configuração do MRTK (Configurar MRTK).
  • Adicione MRTK à cena atual (Adicionar à cena). Use o ARRMixedRealityToolkitConfigurationProfile aqui em vez do perfil sugerido no tutorial.

Importar ativos usados por este tutorial

A partir deste capítulo, implementaremos um padrão básico de model-view-controller para grande parte do material abordado. A parte do modelo do padrão é o código específico da Renderização Remota do Azure e o gerenciamento de estado relacionado à Renderização Remota do Azure. As partes de exibição e controlador do padrão são implementadas usando ativos MRTK e alguns scripts personalizados. É possível usar o modelo neste tutorial sem o view-controller implementado aqui. Essa separação permite que você integre facilmente o código encontrado neste tutorial em seu próprio aplicativo, onde ele assume a parte do controlador de visualização do padrão de design.

Com a introdução do MRTK, há vários scripts, pré-fabricados e ativos que agora podem ser adicionados ao projeto para suportar interações e feedback visual. Esses ativos, conhecidos como Ativos de Tutorial, são agrupados em um Pacote de Ativos Unity, que está incluído no GitHub de Renderização Remota do Azure em '\Unity\TutorialAssets\TutorialAssets.unitypackage'.

  1. Clone ou baixe o repositório git Azure Remote Rendering, se estiver baixando extraia o zip para um local conhecido.
  2. Em seu projeto Unity, escolha Assets -> Import Package -> Custom Package.
  3. No explorador de arquivos, navegue até o diretório onde você clonou ou descompactou o repositório de Renderização Remota do Azure e selecione o .unitypackage encontrado em Unity -> TutorialAssets -> TutorialAssets.unitypackage
  4. Selecione o botão Importar para importar o conteúdo do pacote para o seu projeto.
  5. No Editor Unity, selecione Mixed Reality Toolkit -> Utilities -> Upgrade MRTK Standard Shader for Lightweight Render Pipeline na barra de menu superior e siga as instruções para atualizar o sombreador.

Depois que o MRTK e os Ativos do Tutorial estiverem configurados, verifique se o perfil correto está selecionado.

  1. Selecione o MixedRealityToolkit GameObject na hierarquia de cena.
  2. No Inspetor, sob o componente MixedRealityToolkit , alterne o perfil de configuração para ARRMixedRealityToolkitConfigurationProfile.
  3. Prima Ctrl+S para guardar as alterações.

Esta etapa configura o MRTK, principalmente, com os perfis padrão do HoloLens 2. Os perfis fornecidos são pré-configurados das seguintes maneiras:

  • Desligue o criador de perfil (pressione 9 para ativá-lo/desativá-lo ou diga "Mostrar/Ocultar Profiler" no dispositivo).
  • Desligue o cursor do olhar dos olhos.
  • Habilite os cliques do mouse Unity, para que você possa clicar em elementos da interface do usuário MRTK com o mouse em vez da mão simulada.

Adicionar o menu do aplicativo

A maioria dos controladores de exibição neste tutorial operam contra classes base abstratas em vez de classes concretas. Esse padrão fornece mais flexibilidade e nos permite fornecer os controladores de exibição para você, enquanto ainda ajuda você a aprender o código de Renderização Remota do Azure. Para simplificar, a classe RemoteRenderingCoordinator não tem uma classe abstrata fornecida e seu controlador de exibição opera diretamente contra a classe concreta.

Agora você pode adicionar o AppMenu pré-fabricado à cena, para feedback visual do estado atual da sessão. O AppMenu também apresenta o painel modal que o usuário usa para autorizar o aplicativo a se conectar ao ARR.

  1. Localize o pré-fabricado AppMenu em Assets/RemoteRenderingTutorial/Prefabs/AppMenu

  2. Arraste o pré-fabricado AppMenu para a cena.

  3. Se vir uma caixa de diálogo para o Importador TMP, siga as instruções para Importar TMP Essentials. Em seguida, feche a caixa de diálogo do importador, pois os exemplos e extras não são necessários.

  4. O AppMenu é configurado para se conectar automaticamente e fornecer o modal para consentir em se conectar a uma sessão, para que possamos remover o bypass colocado anteriormente. No RemoteRenderingCoordinator GameObject, remova o bypass para autorização que implementamos anteriormente, pressionando o botão '-' no evento On Request Authorization.

    Remover bypass .

  5. Teste o controlador de visualização pressionando Play no Unity Editor.

  6. No Editor, agora que o MRTK está configurado, você pode usar as teclas WASD para alterar a posição da sua visualização e segurar o botão direito do mouse + mover o mouse para alterar a direção da sua visualização. Tente "dirigir" um pouco pela cena para ter uma ideia dos controles.

  7. No dispositivo, você pode levantar a palma da mão para invocar o AppMenu, no Editor Unity, use a tecla de atalho 'M'.

  8. Se você perdeu o menu de vista, pressione a tecla 'M' para chamar o menu. O menu é colocado perto da câmera para facilitar a interação.

  9. O AppMenu apresenta um elemento UI para autorização à direita do AppMenu. A partir de agora, você deve usar esse elemento da interface do usuário para autorizar o aplicativo a gerenciar sessões de renderização remota.

    Autorização da interface do usuário

  10. Pare o Unity de jogar para continuar com o tutorial.

Gerenciar o estado do modelo

Precisamos de um novo script chamado RemoteRenderedModel que seja para rastrear o estado, responder a eventos, disparar eventos e configuração. Essencialmente, RemoteRenderedModel armazena o caminho remoto para os dados do modelo no modelPath. Ele escuta as alterações de estado no RemoteRenderingCoordinator para ver se ele deve carregar ou descarregar automaticamente o modelo que ele define. O GameObject que tem o RemoteRenderedModel anexado a ele é o pai local para o conteúdo remoto.

Observe que o script RemoteRenderedModel implementa BaseRemoteRenderedModel, incluído de Tutorial Assets. Essa conexão permite que o controlador de exibição de modelo remoto se associe ao seu script.

  1. Crie um novo script chamado RemoteRenderedModel na mesma pasta que RemoteRenderingCoordinator. Substitua todo o conteúdo pelo seguinte código:

    // 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 UnityEngine;
    using UnityEngine.Events;
    
    public class RemoteRenderedModel : BaseRemoteRenderedModel
    {
        public bool AutomaticallyLoad = true;
    
        private ModelState currentModelState = ModelState.NotReady;
    
        [SerializeField]
        [Tooltip("The friendly name for this model")]
        private string modelDisplayName;
        public override string ModelDisplayName { get => modelDisplayName; set => modelDisplayName = value; }
    
        [SerializeField]
        [Tooltip("The URI for this model")]
        private string modelPath;
        public override string ModelPath
        {
            get => modelPath.Trim();
            set => modelPath = value;
        }
    
        public override ModelState CurrentModelState
        {
            get => currentModelState;
            protected set
            {
                if (currentModelState != value)
                {
                    currentModelState = value;
                    ModelStateChange?.Invoke(value);
                }
            }
        }
    
        public override event Action<ModelState> ModelStateChange;
        public override event Action<float> LoadProgress;
        public override Entity ModelEntity { get; protected set; }
    
        public UnityEvent OnModelNotReady = new UnityEvent();
        public UnityEvent OnModelReady = new UnityEvent();
        public UnityEvent OnStartLoading = new UnityEvent();
        public UnityEvent OnModelLoaded = new UnityEvent();
        public UnityEvent OnModelUnloading = new UnityEvent();
    
        public UnityFloatEvent OnLoadProgress = new UnityFloatEvent();
    
        public void Awake()
        {
            // Hook up the event to the Unity event
            LoadProgress += (progress) => OnLoadProgress?.Invoke(progress);
    
            ModelStateChange += HandleUnityStateEvents;
        }
    
        private void HandleUnityStateEvents(ModelState modelState)
        {
            switch (modelState)
            {
                case ModelState.NotReady:  OnModelNotReady?.Invoke();  break;
                case ModelState.Ready:     OnModelReady?.Invoke();     break;
                case ModelState.Loading:   OnStartLoading?.Invoke();   break;
                case ModelState.Loaded:    OnModelLoaded?.Invoke();    break;
                case ModelState.Unloading: OnModelUnloading?.Invoke(); break;
            }
        }
    
        private void Start()
        {
            //Attach to and initialize current state (in case we're attaching late)
            RemoteRenderingCoordinator.CoordinatorStateChange += Instance_CoordinatorStateChange;
            Instance_CoordinatorStateChange(RemoteRenderingCoordinator.instance.CurrentCoordinatorState);
        }
    
        /// <summary>
        /// Listen for state changes on the coordinator, clean up this model's remote objects if we're no longer connected.
        /// Automatically load if required
        /// </summary>
        private void Instance_CoordinatorStateChange(RemoteRenderingCoordinator.RemoteRenderingState state)
        {
            switch (state)
            {
                case RemoteRenderingCoordinator.RemoteRenderingState.RuntimeConnected:
                    CurrentModelState = ModelState.Ready;
                    if (AutomaticallyLoad)
                        LoadModel();
                    break;
                default:
                    UnloadModel();
                    break;
            }
        }
    
        private void OnDestroy()
        {
            RemoteRenderingCoordinator.CoordinatorStateChange -= Instance_CoordinatorStateChange;
            UnloadModel();
        }
    
        /// <summary>
        /// Asks the coordinator to create a model entity and listens for coordinator state changes
        /// </summary>
        [ContextMenu("Load Model")]
        public override async void LoadModel()
        {
            if (CurrentModelState != ModelState.Ready)
                return; //We're already loaded, currently loading, or not ready to load
    
            CurrentModelState = ModelState.Loading;
    
            ModelEntity = await RemoteRenderingCoordinator.instance?.LoadModel(ModelPath, this.transform, SetLoadingProgress);
    
            if (ModelEntity != null)
                CurrentModelState = ModelState.Loaded;
            else
                CurrentModelState = ModelState.Error;
        }
    
        /// <summary>
        /// Clean up the local model instances
        /// </summary>
        [ContextMenu("Unload Model")]
        public override void UnloadModel()
        {
            CurrentModelState = ModelState.Unloading;
    
            if (ModelEntity != null)
            {
                var modelGameObject = ModelEntity.GetOrCreateGameObject(UnityCreationMode.DoNotCreateUnityComponents);
                Destroy(modelGameObject);
                ModelEntity.Destroy();
                ModelEntity = null;
            }
    
            if (RemoteRenderingCoordinator.instance.CurrentCoordinatorState == RemoteRenderingCoordinator.RemoteRenderingState.RuntimeConnected)
                CurrentModelState = ModelState.Ready;
            else
                CurrentModelState = ModelState.NotReady;
        }
    
        /// <summary>
        /// Update the Unity progress event
        /// </summary>
        /// <param name="progressValue"></param>
        public override void SetLoadingProgress(float progressValue)
        {
            LoadProgress?.Invoke(progressValue);
        }
    }
    

Em termos mais básicos, RemoteRenderedModel contém os dados necessários para carregar um modelo (neste caso, o SAS ou builtin:// URI) e rastreia o estado do modelo remoto. Quando é hora de carregar o modelo, o LoadModel método é chamado em RemoteRenderingCoordinator e a entidade que contém o modelo é retornada para referência e descarregamento.

Carregue o modelo de teste

Vamos testar o novo script carregando o modelo de teste novamente. Para este teste, precisamos de um objeto de jogo para conter o script e ser um pai para o modelo de teste, e também precisamos de um estágio virtual que contém o modelo. Usamos um estágio fixo para que o modelo em si ainda possa ser movido mais tarde.

  1. Crie um novo objeto de jogo vazio na cena e nomeie-o ModelStage.

  2. Adicionar um componente World Anchor ao ModelStage

    Adicionar componente WorldAnchor

  3. Crie um novo objeto de jogo vazio como filho de ModelStage e nomeie-o TestModel.

  4. Adicione o script RemoteRenderedModel ao TestModel.

    Adicionar componente RemoteRenderedModel

  5. Preencha o Model Display Name e o Model Path com "TestModel" e "builtin://Engine", respectivamente.

    Especificar detalhes do modelo

  6. Posicione o objeto TestModel na frente da câmera, na posição x = 0, y = 0, z = 3.

    Objeto de posição

  7. Verifique se AutomaticallyLoad está ativado.

  8. Pressione Play no Unity Editor para testar o aplicativo.

  9. Conceda autorização clicando no botão Conectar para permitir que o aplicativo crie uma sessão, conecte-se a ela e carregue automaticamente o modelo.

Observe o Console enquanto o aplicativo progride em seus estados. Tenha em mente que alguns estados podem levar algum tempo para serem concluídos e pode não haver atualizações de progresso por um tempo. Eventualmente, você vê logs do modelo carregando e, logo após o modelo de teste renderizado na cena.

Tente mover e girar o TestModel GameObject por meio da Transformação no Inspetor ou na visualização Cena e observe as transformações na visualização Jogo.

Log da unidade

Provisionar armazenamento de Blob no Azure e ingestão de modelo personalizado

Agora podemos tentar carregar o seu próprio modelo. Para fazer isso, você precisa configurar o Armazenamento de Blob no Azure, carregar e converter um modelo e, em seguida, carregar o modelo usando o script RemoteRenderedModel . As etapas de carregamento do modelo personalizado podem ser ignoradas com segurança se você não tiver seu próprio modelo para carregar no momento.

Siga as etapas especificadas no Guia de início rápido: converter um modelo para renderização. Ignore a seção Inserir novo modelo no aplicativo de exemplo de início rápido para este tutorial. Depois de ter o URI de Assinatura de Acesso Compartilhado (SAS) do modelo ingerido, continue.

Carregar e renderizar um modelo personalizado

  1. Crie um novo GameObject vazio na cena e nomeie-o de forma semelhante ao seu modelo personalizado.

  2. Adicione o script RemoteRenderedModel ao GameObject recém-criado.

    Adicionar componente RemoteRenderedModel

  3. Preencha o com um nome apropriado para o Model Display Name seu modelo.

  4. Preencha o Model Path URI com a Assinatura de Acesso Compartilhado (SAS) do modelo que você criou na etapa Provisionar Armazenamento de Blob no Azure e ingestão de modelo personalizado.

  5. Posicione o GameObject na frente da câmera, na posição x = 0, y = 0, z = 3.

  6. Verifique se AutomaticallyLoad está ativado.

  7. Pressione Play no Unity Editor para testar o aplicativo.

    O console mostra o estado atual da sessão e também as mensagens de progresso de carregamento do modelo, uma vez que a sessão é conectada.

  8. Remova o objeto de modelo personalizado da cena. A melhor experiência para este tutorial é com o modelo de teste. Embora vários modelos sejam suportados no ARR, este tutorial foi escrito para oferecer melhor suporte a um único modelo remoto de cada vez.

Próximos passos

Agora você pode carregar seus próprios modelos na Renderização Remota do Azure e visualizá-los em seu aplicativo! Em seguida, guiamo-lo através da manipulação dos seus modelos.