HoloLens (1º gênero) e Azure 305: Funções e armazenamento


Nota

Os tutoriais da Mixed Reality Academy foram desenhados com HoloLens (1º género) e Auscultadores Imersivos de Realidade Mista em mente. Como tal, sentimos que é importante deixar estes tutoriais no lugar para os desenvolvedores que ainda estão à procura de orientação no desenvolvimento para esses dispositivos. Estes tutoriais não serão atualizados com os mais recentes instrumentos ou interações a serem utilizados para HoloLens 2. Serão mantidos para continuar a trabalhar nos dispositivos suportados. Haverá uma nova série de tutoriais que serão publicados no futuro que demonstrarão como se desenvolver para HoloLens 2. Este aviso será atualizado com um link para esses tutoriais quando forem publicados.


produto final -início

Neste curso, você aprenderá a criar e usar funções Azure e armazenar dados com um recurso Azure Armazenamento, dentro de uma aplicação de realidade mista.

Azure Functions é um serviço da Microsoft, que permite aos desenvolvedores executar pequenas peças de código, 'funções', em Azure. Isto fornece uma maneira de delegar o trabalho na nuvem, em vez da sua aplicação local, que pode ter muitos benefícios. A Azure Functions suporta várias línguas de desenvolvimento, incluindo C#, F#, Node.js, Java e PHP. Para mais informações, visite o artigo Azure Functions.

O Azure Armazenamento é um serviço de cloud da Microsoft, que permite aos desenvolvedores armazenar dados, com o seguro de que estará altamente disponível, seguro, durável, escalável e redundante. Isto significa que a Microsoft tratará de toda a manutenção e problemas críticos para si. Para mais informações, visite o artigo Armazenamento Azure.

Depois de concluído este curso, terá uma aplicação de auscultadores imersivos de realidade mista que poderá fazer o seguinte:

  1. Deixe o utilizador olhar ao redor de uma cena.
  2. Desencadeie a desova de objetos quando o utilizador olhar para um 'botão' 3D.
  3. Os objetos gerados serão escolhidos por uma Função Azure.
  4. À medida que cada objeto é gerado, a aplicação armazenará o tipo de objeto num Ficheiro Azure,localizado em Azure Armazenamento.
  5. Ao carregar uma segunda vez, os dados do Arquivo Azure serão recuperados e utilizados para reproduzir as ações de desova da instância anterior da aplicação.

Na sua aplicação, cabe-lhe a si integrar os resultados com o seu design. Este curso destina-se a ensinar-lhe como integrar um Serviço Azure com o seu Project de Unidade. É seu trabalho usar o conhecimento que ganha com este curso para melhorar a sua aplicação de realidade mista.

Suporte de dispositivos

Curso HoloLens Auscultadores imersivos
MR e Azure 305: Funções e armazenamento ✔️ ✔️

Nota

Embora este curso se centre principalmente em auscultadores imersivos Windows Mixed Reality (VR), também pode aplicar o que aprende neste curso para Microsoft HoloLens. À medida que acompanha o curso, verá notas sobre quaisquer alterações que possa ter de empregar para apoiar HoloLens.

Pré-requisitos

Nota

Este tutorial é projetado para desenvolvedores que têm experiência básica com Unidade e C#. Tenha também em atenção que os pré-requisitos e instruções escritas neste documento representam o que foi testado e verificado no momento da escrita (maio de 2018). Você é livre de usar o software mais recente, como listado dentro do artigo de instalação do artigo de ferramentas, embora não deva presumir-se que as informações neste curso irão perfeitamente corresponder ao que você vai encontrar em software mais recente do que o listado abaixo.

Recomendamos o seguinte hardware e software para este curso:

Antes de começar

Para evitar encontrar problemas na construção deste projeto, sugere-se fortemente que crie o projeto mencionado neste tutorial numa pasta de raiz ou de raiz (os caminhos de pasta longa podem causar problemas no tempo de construção).

Capítulo 1 - O Portal Azure

Para utilizar o Serviço Azure Armazenamento,terá de criar e configurar uma Conta Armazenamento no portal Azure.

  1. Faça login no Portal Azure.

    Nota

    Se ainda não tiver uma conta Azure, terá de criar uma. Se estiver a seguir este tutorial numa sala de aula ou em laboratório, peça ao seu instrutor ou a um dos proctors para ajudar a criar a sua nova conta.

  2. Assim que iniciar sessão, clique em New no canto superior esquerdo e procure Armazenamento conta, e clique em Entrar.

    pesquisa de armazenamento azul

    Nota

    A palavra Novo pode ter sido substituída por Criar um recurso,em portais mais recentes.

  3. A nova página fornecerá uma descrição do serviço de conta Azure Armazenamento. Na parte inferior esquerda deste pedido, selecione o botão Criar, para criar uma associação com este serviço.

    criar serviço

  4. Uma vez clicado no Criar:

    1. Insira um Nome para a sua conta, esteja ciente de que este campo só aceita números e letras minúsculas.

    2. Para o modelo de implementação, selecione Resource manager.

    3. Para o tipo conta, selecione Armazenamento (finalidade geral v1).

    4. Determine a localização do seu grupo de recursos (se estiver a criar um novo Grupo de Recursos). A localização seria idealmente na região onde a aplicação iria decorrer. Alguns ativos da Azure só estão disponíveis em certas regiões.

    5. Para replicação,selecione Read-access-geo-redundante storage (RA-GRS).

    6. Em Desempenho, selecione Standard.

    7. Deixe a transferência Secure necessária como Desativada.

    8. Selecione uma subscrição.

    9. Escolha um Grupo de Recursos ou crie um novo. Um grupo de recursos fornece uma forma de monitorizar, controlar o acesso, fornecer e gerir a faturação para uma recolha de ativos da Azure. Recomenda-se manter todos os serviços Azure associados a um único projeto (por exemplo, como estes laboratórios) sob um grupo de recursos comuns).

      Se desejar ler mais sobre os Grupos de Recursos Azure, visite o artigo do grupo de recursos.

    10. Também terá de confirmar que compreendeu os Termos e Condições aplicados a este Serviço.

    11. Selecione Criar.

      informação de serviço de entrada

  5. Uma vez clicado no Create,terá de esperar pela criação do serviço, pode demorar um minuto.

  6. Uma notificação aparecerá no portal assim que a instância de Serviço for criada.

    nova notificação no portal azul

  7. Clique nas notificações para explorar a sua nova instância de Serviço.

    ir para o recurso

  8. Clique no botão 'Ir ao recurso' na notificação para explorar a sua nova instância de Serviço. Você será levado para a sua nova Armazenamento caso de serviço de conta.

    chaves de acesso

  9. Clique nas teclas de Acesso, para revelar os pontos finais deste serviço na nuvem. Utilize Bloco de notas ou similares para copiar uma das suas chaves para utilização posterior. Além disso, note o valor da cadeia Connection, uma vez que será utilizado na classe AzureServices, que irá criar mais tarde.

    cadeia de ligação de cópia

Capítulo 2 - Criação de uma Função Azure

Irá agora escrever umaFunçãoAzureno Serviço Azure.

Pode utilizar uma Função Azure para fazer quase tudo o que faria com uma função clássica no seu código, sendo a diferença que esta função pode ser acedida por qualquer aplicação que tenha credenciais para aceder à sua Conta Azure.

Para criar uma Função Azure:

  1. A partir do seu Portal Azure,clique em Novo no canto superior esquerdo e procure app de função, e clique em Entrar.

    criar app de função

    Nota

    A palavra Novo pode ter sido substituída por Criar um recurso,em portais mais recentes.

  2. A nova página fornecerá uma descrição do serviço Azure Function App. Na parte inferior esquerda deste pedido, selecione o botão Criar, para criar uma associação com este serviço.

    informação de aplicação de função

  3. Uma vez clicado no Criar:

    1. Fornecer um nome de App. Apenas podem ser utilizadas letras e números aqui (é permitida a caixa superior ou inferior).

    2. Selecione a sua SubscriçãoPreferida.

    3. Escolha um Grupo de Recursos ou crie um novo. Um grupo de recursos fornece uma forma de monitorizar, controlar o acesso, fornecer e gerir a faturação para uma recolha de ativos da Azure. Recomenda-se manter todos os serviços Azure associados a um único projeto (por exemplo, como estes laboratórios) sob um grupo de recursos comuns).

      Se desejar ler mais sobre os Grupos de Recursos Azure, visite o artigo do grupo de recursos.

    4. Para este exercício, selecione Windows como o SISTEMAescolhido .

    5. Selecione Plano de Consumo para o Plano de Hospedagem.

    6. Determine a localização do seu grupo de recursos (se estiver a criar um novo Grupo de Recursos). A localização seria idealmente na região onde a aplicação iria decorrer. Alguns ativos da Azure só estão disponíveis em certas regiões. Para obter um melhor desempenho, selecione a mesma região que a conta de armazenamento.

    7. Para Armazenamento, selecione Use existente, e, em seguida, usando o menu dropdown, encontre o seu armazenamento previamente criado.

    8. Deixe a aplicação Informações para este exercício.

      detalhes da aplicação da função de entrada

  4. Clique no botão Criar.

  5. Uma vez clicado no Create,terá de esperar pela criação do serviço, pode demorar um minuto.

  6. Uma notificação aparecerá no portal assim que a instância de Serviço for criada.

    nova notificação do portal azul

  7. Clique nas notificações para explorar a sua nova instância de Serviço.

    ir para app de função de recurso

  8. Clique no botão 'Ir ao recurso' na notificação para explorar a sua nova instância de Serviço. Será levado para a sua nova instância de serviço de Aplicação de Função.

  9. No painel de instrumentos da Aplicação de Funções, passe o rato sobre funções,encontrado dentro do painel à esquerda e, em seguida, clique no símbolo + (mais).

    criar nova função

  10. Na página seguinte, certifique-se de que o Webhook + API está selecionado, e para escolher um idioma, selecione CSharp,pois este será o idioma utilizado para este tutorial. Por último, clique no botão Criar esta função.

    selecione csharp de gancho web

  11. Deve ser levado para a página de código (run.csx), se não for, clique na função recém-criada na lista de Funções dentro do painel à esquerda.

    abrir nova função

  12. Copie o seguinte código para a sua função. Esta função simplesmente retornará um inteiro aleatório entre 0 e 2 quando chamado. Não se preocupe com o código existente, sinta-se à vontade para colar por cima.

        using System.Net;
        using System.Threading.Tasks;
    
        public static int Run(CustomObject req, TraceWriter log)
        {
            Random rnd = new Random();
            int randomInt = rnd.Next(0, 3);
            return randomInt;
        }
    
        public class CustomObject
        {
            public String name {get; set;}
        }
    
  13. Selecione Guardar.

  14. O resultado deve parecer a imagem abaixo.

  15. Clique em Obter URL de função e tome nota do ponto final exibido. Terá de inseri-lo na classe AzureServices que irá criar mais tarde neste curso.

    Obtenha o ponto final da função

    Inserir ponto final de função

Capítulo 3 - Criação do projeto Unidade

Segue-se um conjunto típico para o desenvolvimento com a Realidade Mista, e como tal, é um bom modelo para outros projetos.

Configurar e testar os auscultadores imersivos de realidade mista.

Nota

Não vai precisar de controladores de movimento para este curso. Se precisar de suporte para configurar os auscultadores imersivos, visite o artigo de configuração da realidade mista.

  1. Abra a unidade e clique em Novo.

    Criar novo projeto de unidade

  2. Agora terá de fornecer um nome Project de unidade. Insira MR_Azure_Functions. Certifique-se de que o tipo de projeto está definido para 3D. Desa esta medida para um local apropriado para si (lembre-se, mais perto dos diretórios de raiz é melhor). Em seguida, clique em Criar projeto.

    Dar um nome ao novo projeto de unidade

  3. Com a Unidade aberta, vale a pena verificar se o Script Editor padrão está definido para Visual Studio. Vá para EditarPreferências e, em seguida, a partir da nova janela, navegue para Ferramentas Externas. Alterar editor de script externo para Visual Studio 2017. Feche a janela Preferências.

    definir estúdio visual como editor de script

  4. Em seguida, vá ao FileBuild Definições e altere a plataforma para Universal Windows Platform, clicando no botão 'Plataforma Switch'.

    mudar plataforma para uwp

  5. Vá ao FileBuild Definições e certifique-se de que:

    1. O dispositivo-alvo está definido para qualquer dispositivo.

      Para Microsoft HoloLens, desaponte o dispositivo alvo para HoloLens.

    2. O Tipo de Construção está definido para D3D

    3. SDK está definido para as últimas instalações

    4. Visual Studio versão está definida para o mais recente instalado

    5. Build and Run está definido para máquina local

    6. Salve a cena e adicione-a à construção.

      1. Faça-o selecionando Add Open Scenes. Aparecerá uma janela de salvamento.

        adicionar cenas abertas

      2. Crie uma nova pasta para isto e qualquer futuro, cena, em seguida, selecione o botão nova pasta, para criar uma nova pasta, nomeie-a Cenas.

        criar pasta de cenas

      3. Abra a pasta Cenas recém-criada e, em seguida, no nome Ficheiro: campo de texto, tipo FunçõesCene,em seguida, prima Guardar.

        Salvar cena de funções

  6. As definições restantes, em Build Definições,devem ser deixadas como padrão por enquanto.

    Deixe as definições de construção predefinidos

  7. Na janela Build Definições, clique no botão Player Definições, isto abrirá o painel relacionado no espaço onde o Inspetor está localizado.

    definições de jogadores no inspetor

  8. Neste painel, é necessário verificar algumas definições:

    1. No separador Other Definições:

      1. A versão de tempo de execução de script deve ser experimental (.NET 4.6 Equivalent), o que irá desencadear a necessidade de reiniciar o Editor.
      2. Scripting Backend deve ser .NET
      3. O nível de compatibilidade da API deve ser .NET 4.6
    2. No separador Definições de Publicação, em Capacidades,verifique:

      • InternetClient

        definir capacidades

    3. Mais abaixo no painel, em XR Definições (encontrado abaixo Definições de publicação),marque o Suporte à Realidade Virtual, certifique-se de que o Windows Mixed Reality SDK é adicionado.

      definir definições de XR

  9. Back in Build DefiniçõesUnity C# Os projetos já não estão acinzentados; marque a caixa de verificação ao lado desta.

    projetos tick c#

  10. Feche a janela Build Definições.

  11. Guarde a sua Cena e Project(CENADE SALVAMENTO DE FICHEIROS /PROJETO DE SALVAMENTO DE FICHEIROS).

Capítulo 4 - Configuração da Câmara Principal

Importante

Se desejar saltar os componentes da Unidade Configurar componentes deste curso e continuar em linha reta em código, sinta-se livre para descarregar esta .unitypackage, e importá-la para o seu projeto como um Pacote Personalizado. Isto também conterá os DLLs do próximo capítulo. Após a importação, continue a partir do capítulo 7.

  1. No Painel hierarquia, encontrará um objeto chamado Câmara Principal, este objeto representa o seu ponto de vista de "cabeça" uma vez que está "dentro" da sua aplicação.

  2. Com o Painel de Unidade à sua frente, selecione o GameObject da Câmara Principal. Irá notar que o Painel de Inspetores (geralmente encontrado à direita, dentro do Painel de Instrumentos) mostrará os vários componentes desse GameObject, com a Transform no topo, seguido da Câmara, e alguns outros componentes. Terá de reiniciar a Transformação da Câmara Principal, para que esta esteja corretamente posicionada.

  3. Para isso, selecione o ícone De Engrenagem ao lado do componente Transform da Câmara e selecione Reset.

    transformar reset

  4. Em seguida, atualize o componente Transform para parecer:

    TRANSFORMAR - POSIÇÃO
    X Y Z
    0 1 0
    TRANSFORMAR - ROTAÇÃO
    X Y Z
    0 0 0
    TRANSFORMAR - ESCALA
    X Y Z
    1 1 1

    definir câmera transformar

Capítulo 5 - Criação da cena da Unidade

  1. Clique à direita numa área vazia do Painel hierárquico,sob objeto 3D,adicione um plano.

    criar novo plano

  2. Com o objeto do Avião selecionado, altere os seguintes parâmetros no Painel de Inspetor:

    TRANSFORMAR - POSIÇÃO
    X Y Z
    0 0 4
    TRANSFORMAR - ESCALA
    X Y Z
    10 1 10

    definir posição e escala do plano

    vista da cena do avião

  3. Clique à direita numa área vazia do Painel hierárquico,sob o Objeto 3D,adicione um cubo.

    1. Mude o nome do Cubo para GazeButton (com o Cubo selecionado, prima 'F2').

    2. Alterar os seguintes parâmetros no Painel de Inspetores:

      TRANSFORMAR - POSIÇÃO
      X Y Z
      0 3 5

      definir transformar botão de olhar

      vista de cena de botão de olhar

    3. Clique no botão 'Drop-down' da Tag e clique em Adicionar Tag para abrir o Painel de Camadas de Etiquetas.

      adicionar nova etiqueta

      selecionar mais

    4. Selecione o botão + (mais) e no campo Nome da Nova Etiqueta, insira GazeButtone prima Save.

      nome nova tag

    5. Clique no objeto GazeButton no Painel Hierárquico, e no Painel de Inspetores,atribua a etiqueta GazeButton recém-criada.

      atribuir botão de olhar a nova tag

  4. Clique com o botão direito no objeto GazeButton, no Painel hierárquico,e adicione um GameObject vazio (que será adicionado como um objeto infantil).

  5. Selecione o novo objeto e rebatize-o ComoSpawnPoint.

    1. Alterar os seguintes parâmetros no Painel de Inspetores:

      TRANSFORMAR - POSIÇÃO
      X Y Z
      0 -1 0

      atualização forma de desova ponto de transformação

      forma vista de cena ponto de desova

  6. Em seguida, irá criar um objeto de Texto 3D para fornecer feedback sobre o estado do serviço Azure.

    Clique no GazeButton no Painel da Hierarquia novamente e adicione um objeto de texto 3D objeto3D em criança.

    criar novo objeto de texto 3D

  7. Mude o nome do objeto de texto 3D para AzureStatusText.

  8. Alterar o objeto AzureStatusText Transforme da seguinte forma:

    TRANSFORMAR - POSIÇÃO
    X Y Z
    0 0 -0,6
    TRANSFORMAR - ESCALA
    X Y Z
    0.1 0.1 0.1

    Nota

    Não se preocupe se parecer fora do centro, pois este será corrigido quando o componente de malha de texto abaixo for atualizado.

  9. Altere o componente de malha de texto para corresponder ao seguinte:

    componente de malha de texto definido

    Dica

    A cor selecionada aqui é a cor Hex: 000000FF, emborasinta-se livre para escolher a sua, apenas certifique-se de que é legível.

  10. A sua estrutura do Painel Hierárquica deve agora ser assim:

    Malha de texto na hierarquia

  11. A sua cena deve agora ser assim:

    Malha de texto na vista de cena

Capítulo 6 - Import Azure Armazenamento for Unitity

Você estará usando Azure Armazenamento for Unitity (que por si só aproveita o .Net SDK para Azure). Pode ler mais sobre isso no artigo da Azure Armazenamento for Unitity.

Existe atualmente uma questão conhecida na Unidade que exige que os plugins sejam reconfigurados após a importação. Estes passos (4 - 7 nesta secção) deixarão de ser necessários após a solução do erro.

Para importar o SDK para o seu próprio projeto, certifique-se de que descarregou a mais recente '.unitypackage' de GitHub. Em seguida, faça o seguinte:

  1. Adicione o ficheiro .unitypackage à Unidade utilizando a opção de menu pacote personalizado de pacote de importação de ativos.

  2. Na caixa 'Pacote de Unidade de Importação' que aparece, pode selecionar tudo em pluginArmazenamento. Desmarque todo o resto, já que não é necessário para este curso.

    importar para embalar

  3. Clique no botão Importar para adicionar os itens ao seu projeto.

  4. Aceda à pasta Armazenamento sob os Plugins,na vista Project, e selecione apenasos seguintes plugins:

    • Microsoft.Data.Edm

    • Microsoft.Data.OData

    • Microsoft.WindowsAzure.Storage

    • Newtonsoft.Json

    • Sistema.Espacial

      desmarque qualquer plataforma

  5. Com estes plugins específicos selecionados,desmarquequalquer Plataforma e desmarqueoWSAPlayer e clique em Aplicar.

    aplicar dlls plataforma

    Nota

    Estamos marcando estes plugins particulares para serem usados apenas no Editor de Unidade. Isto porque existem diferentes versões dos mesmos plugins na pasta WSA que serão usadas após a exportação do projeto da Unidade.

  6. Na pasta plugin Armazenamento, selecione apenas:

    • Microsoft.Data.Services.Client

      definir não processar para dlls

  7. Verifique a caixa 'Não processar' na plataforma Definições e clique em Aplicar.

    não aplicar nenhum processamento

    Nota

    Estamos a marcar este plugin "Don't process" porque o patcher de montagem unidade tem dificuldade em processar este plugin. O plugin continuará a funcionar mesmo que não seja processado.

Capítulo 7 - Criar a classe AzureServices

A primeira classe que vai criar é a classe AzureServices.

A classe AzureServices será responsável por:

  • Armazenar credenciais de Conta Azure.

  • Chamando a sua Função de App Azure.

  • O upload e download do ficheiro de dados no seu Azure Cloud Armazenamento.

Para criar esta Classe:

  1. Clique com o botão direito na pasta de ativos, localizada no painel Project, criepasta. Nomeie as pastas Scripts.

    criar nova pasta

    pasta de chamadas - scripts

  2. Clique duas vezes na pasta acabada de criar, para abri-la.

  3. Clique com o botão direito dentro da pasta, CrieO Script C#. Ligue para o script AzureServices.

  4. Clique duas vezes na nova classe AzureServices para abri-la com Visual Studio.

  5. Adicione os seguintes espaços de nome ao topo dos AzureServices:

        using System;
        using System.Threading.Tasks;
        using UnityEngine;
        using Microsoft.WindowsAzure.Storage;
        using Microsoft.WindowsAzure.Storage.File;
        using System.IO;
        using System.Net;
    
  6. Adicione os seguintes Campos de Inspetor dentro da classe AzureServices:

        /// <summary>
        /// Provides Singleton-like behavior to this class.
        /// </summary>
        public static AzureServices instance;
    
        /// <summary>
        /// Reference Target for AzureStatusText Text Mesh object
        /// </summary>
        public TextMesh azureStatusText;
    
  7. Em seguida, adicione as seguintes variáveis de membro dentro da classe AzureServices:

        /// <summary>
        /// Holds the Azure Function endpoint - Insert your Azure Function
        /// Connection String here.
        /// </summary>
    
        private readonly string azureFunctionEndpoint = "--Insert here you AzureFunction Endpoint--";
    
        /// <summary>
        /// Holds the Storage Connection String - Insert your Azure Storage
        /// Connection String here.
        /// </summary>
        private readonly string storageConnectionString = "--Insert here you AzureStorage Connection String--";
    
        /// <summary>
        /// Name of the Cloud Share - Hosts directories.
        /// </summary>
        private const string fileShare = "fileshare";
    
        /// <summary>
        /// Name of a Directory within the Share
        /// </summary>
        private const string storageDirectory = "storagedirectory";
    
        /// <summary>
        /// The Cloud File
        /// </summary>
        private CloudFile shapeIndexCloudFile;
    
        /// <summary>
        /// The Linked Storage Account
        /// </summary>
        private CloudStorageAccount storageAccount;
    
        /// <summary>
        /// The Cloud Client
        /// </summary>
        private CloudFileClient fileClient;
    
        /// <summary>
        /// The Cloud Share - Hosts Directories
        /// </summary>
        private CloudFileShare share;
    
        /// <summary>
        /// The Directory in the share that will host the Cloud file
        /// </summary>
        private CloudFileDirectory dir;
    

    Importante

    Certifique-se de que substitui os valores de extremidade e de cadeia de ligação com os valores do seu armazenamento Azure, encontrados no Portal Azure

  8. O código para métodos de despertar e arranque() agora precisa ser adicionado. Estes métodos serão chamados quando a classe rubricar:

        private void Awake()
        {
            instance = this;
        }
    
        // Use this for initialization
        private void Start()
        {
            // Set the Status text to loading, whilst attempting connection to Azure.
            azureStatusText.text = "Loading...";
        }
    
        /// <summary>
        /// Call to the Azure Function App to request a Shape.
        /// </summary>
        public async void CallAzureFunctionForNextShape()
        {
    
        }
    

    Importante

    Preencheremos o código de CallAzureFunctionForNextShape numfuturo Capítulo.

  9. Elimine o método 'Atualizar)() uma vez que esta classe não a utilizará.

  10. Guarde as suas mudanças na Visual Studio e, em seguida, regresse à Unidade.

  11. Clique e arraste a classe AzureServices da pasta Scripts para o objeto da Câmara Principal no Painel hierarquia.

  12. Selecione a Câmara Principal, em seguida, pegue o objeto infantil AzureStatusText por baixo do objeto GazeButton, e coloque-o dentro do campo alvo de referência AzureStatusText, no Inspetor,para fornecer a referência ao script AzureServices.

    atribuir alvo de referência de texto de estado azul

Capítulo 8 - Criar a classe ShapeFactory

O próximo guião a criar é a classe ShapeFactory. O papel desta classe é criar uma nova forma, quando solicitada, e manter uma história das formas criadas numa Lista de História da Forma. Sempre que uma forma é criada, a lista De História da Forma é atualizada na classe AzureService e depois armazenada no seu Azure Armazenamento. Quando a aplicação começa, se um ficheiro armazenado for encontrado no seu Azure Armazenamento, a lista de História da Forma é recuperada e reproduzida, com o objeto de Texto 3D a fornecer se a forma gerada é de armazenamento ou nova.

Para criar esta classe:

  1. Vá à pasta Scripts que criou anteriormente.

  2. Clique com o botão direito dentro da pasta, CrieO Script C#. Ligue para o script ShapeFactory.

  3. Clique duas vezes no novo script ShapeFactory para abri-lo com Visual Studio.

  4. Certifique-se de que a classe ShapeFactory inclui os seguintes espaços de nome:

        using System.Collections.Generic;
        using UnityEngine;
    
  5. Adicione as variáveis apresentadas abaixo à classe ShapeFactory e substitua as funções Iniciar() e Despertar() pelas seguintes:

        /// <summary>
        /// Provide this class Singleton-like behaviour
        /// </summary>
        [HideInInspector]
        public static ShapeFactory instance;
    
        /// <summary>
        /// Provides an Inspector exposed reference to ShapeSpawnPoint
        /// </summary>
        [SerializeField]
        public Transform spawnPoint;
    
        /// <summary>
        /// Shape History Index
        /// </summary>
        [HideInInspector]
        public List<int> shapeHistoryList;
    
        /// <summary>
        /// Shapes Enum for selecting required shape
        /// </summary>
        private enum Shapes { Cube, Sphere, Cylinder }
    
        private void Awake()
        {
            instance = this;
        }
    
        private void Start()
        {
            shapeHistoryList = new List<int>();
        }
    
  6. O método CreateShape gera as formas primitivas, com base no parâmetro inteiro fornecido. O parâmetro Boolean é usado para especificar se a forma atualmente criada é de armazenamento, ou nova. Coloque o seguinte código na sua classe ShapeFactory, abaixo dos métodos anteriores:

        /// <summary>
        /// Use the Shape Enum to spawn a new Primitive object in the scene
        /// </summary>
        /// <param name="shape">Enumerator Number for Shape</param>
        /// <param name="storageShape">Provides whether this is new or old</param>
        internal void CreateShape(int shape, bool storageSpace)
        {
            Shapes primitive = (Shapes)shape;
            GameObject newObject = null;
            string shapeText = storageSpace == true ? "Storage: " : "New: ";
    
            AzureServices.instance.azureStatusText.text = string.Format("{0}{1}", shapeText, primitive.ToString());
    
            switch (primitive)
            {
                case Shapes.Cube:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
                break;
    
                case Shapes.Sphere:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                break;
    
                case Shapes.Cylinder:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
                break;
            }
    
            if (newObject != null)
            {
                newObject.transform.position = spawnPoint.position;
    
                newObject.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
    
                newObject.AddComponent<Rigidbody>().useGravity = true;
    
                newObject.GetComponent<Renderer>().material.color = UnityEngine.Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f);
            }
        }
    
  7. Certifique-se de guardar as suas alterações na Visual Studio antes de regressar à Unidade.

  8. De volta ao Editor de Unidade, clique e arraste a classe ShapeFactory da pasta Scripts para o objeto da Câmara Principal no Painel hierarquia.

  9. Com a Câmara Principal selecionada, notará que o componente de script ShapeFactory está a faltar à referência Spawn Point. Para corrigi-lo, arraste o objeto ShapeSpawnPoint do Painel de Hierarquia para o alvo de referência do Ponto de Desova.

    definir meta de referência de fábrica de forma

Capítulo 9 - Criar a classe Gaze

O último guião que precisas de criar é a aula de Gaze.

Esta classe é responsável pela criação de um Raycast que será projetado para a frente a partir da Câmara Principal, para detetar qual o objeto que o utilizador está a analisar. Neste caso, o Raycast terá de identificar se o utilizador está a olhar para o objeto GazeButton na cena e desencadear um comportamento.

Para criar esta Classe:

  1. Vá à pasta Scripts que criou anteriormente.

  2. Clique à direita no Painel Project, CrieO Script C#. Chame o guião Gaze.

  3. Clique duas vezes no novo script Gaze para abri-lo com Visual Studio.

  4. Certifique-se de que o seguinte espaço de nome está incluído no topo do script:

        using UnityEngine;
    
  5. Em seguida, adicione as seguintes variáveis dentro da classe Gaze:

        /// <summary>
        /// Provides Singleton-like behavior to this class.
        /// </summary>
        public static Gaze instance;
    
        /// <summary>
        /// The Tag which the Gaze will use to interact with objects. Can also be set in editor.
        /// </summary>
        public string InteractibleTag = "GazeButton";
    
        /// <summary>
        /// The layer which will be detected by the Gaze ('~0' equals everything).
        /// </summary>
        public LayerMask LayerMask = ~0;
    
        /// <summary>
        /// The Max Distance the gaze should travel, if it has not hit anything.
        /// </summary>
        public float GazeMaxDistance = 300;
    
        /// <summary>
        /// The size of the cursor, which will be created.
        /// </summary>
        public Vector3 CursorSize = new Vector3(0.05f, 0.05f, 0.05f);
    
        /// <summary>
        /// The color of the cursor - can be set in editor.
        /// </summary>
        public Color CursorColour = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
    
        /// <summary>
        /// Provides when the gaze is ready to start working (based upon whether
        /// Azure connects successfully).
        /// </summary>
        internal bool GazeEnabled = false;
    
        /// <summary>
        /// The currently focused object.
        /// </summary>
        internal GameObject FocusedObject { get; private set; }
    
        /// <summary>
        /// The object which was last focused on.
        /// </summary>
        internal GameObject _oldFocusedObject { get; private set; }
    
        /// <summary>
        /// The info taken from the last hit.
        /// </summary>
        internal RaycastHit HitInfo { get; private set; }
    
        /// <summary>
        /// The cursor object.
        /// </summary>
        internal GameObject Cursor { get; private set; }
    
        /// <summary>
        /// Provides whether the raycast has hit something.
        /// </summary>
        internal bool Hit { get; private set; }
    
        /// <summary>
        /// This will store the position which the ray last hit.
        /// </summary>
        internal Vector3 Position { get; private set; }
    
        /// <summary>
        /// This will store the normal, of the ray from its last hit.
        /// </summary>
        internal Vector3 Normal { get; private set; }
    
        /// <summary>
        /// The start point of the gaze ray cast.
        /// </summary>
        private Vector3 _gazeOrigin;
    
        /// <summary>
        /// The direction in which the gaze should be.
        /// </summary>
        private Vector3 _gazeDirection;
    

Importante

Algumas destas variáveis poderão ser editadas no Editor.

  1. O código para os métodos Despertar e Arranque() tem agora de ser adicionado.

        /// <summary>
        /// The method used after initialization of the scene, though before Start().
        /// </summary>
        private void Awake()
        {
            // Set this class to behave similar to singleton
            instance = this;
        }
    
        /// <summary>
        /// Start method used upon initialization.
        /// </summary>
        private void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
  2. Adicione o seguinte código, que criará um objeto cursor no início, juntamente com o método Update() que irá executar o método Raycast, juntamente com o facto de estar onde o boolean GazeEnabled é alternado:

        /// <summary>
        /// Method to create a cursor object.
        /// </summary>
        /// <returns></returns>
        private GameObject CreateCursor()
        {
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            newCursor.SetActive(false);
    
            // Remove the collider, so it doesn't block raycast.
            Destroy(newCursor.GetComponent<SphereCollider>());
            newCursor.transform.localScale = CursorSize;
    
            newCursor.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Diffuse"))
            {
                color = CursorColour
            };
    
            newCursor.name = "Cursor";
    
            newCursor.SetActive(true);
    
            return newCursor;
        }
    
        /// <summary>
        /// Called every frame
        /// </summary>
        private void Update()
        {
            if(GazeEnabled == true)
            {
                _gazeOrigin = Camera.main.transform.position;
    
                _gazeDirection = Camera.main.transform.forward;
    
                UpdateRaycast();
            }
        }
    
  3. Em seguida, adicione o método UpdateRaycast,() que irá projetar um Raycast e detetar o alvo de impacto.

        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            _oldFocusedObject = FocusedObject;
    
            RaycastHit hitInfo;
    
            // Initialise Raycasting.
            Hit = Physics.Raycast(_gazeOrigin,
                _gazeDirection,
                out hitInfo,
                GazeMaxDistance, LayerMask);
    
            HitInfo = hitInfo;
    
            // Check whether raycast has hit.
            if (Hit == true)
            {
                Position = hitInfo.point;
    
                Normal = hitInfo.normal;
    
                // Check whether the hit has a collider.
                if (hitInfo.collider != null)
                {
                    // Set the focused object with what the user just looked at.
                    FocusedObject = hitInfo.collider.gameObject;
                }
                else
                {
                    // Object looked on is not valid, set focused gameobject to null.
                    FocusedObject = null;
                }
            }
            else
            {
                // No object looked upon, set focused gameobject to null.
                FocusedObject = null;
    
                // Provide default position for cursor.
                Position = _gazeOrigin + (_gazeDirection * GazeMaxDistance);
    
                // Provide a default normal.
                Normal = _gazeDirection;
            }
    
            // Lerp the cursor to the given position, which helps to stabilize the gaze.
            Cursor.transform.position = Vector3.Lerp(Cursor.transform.position, Position, 0.6f);
    
            // Check whether the previous focused object is this same 
            //    object. If so, reset the focused object.
            if (FocusedObject != _oldFocusedObject)
            {
                ResetFocusedObject();
    
                if (FocusedObject != null)
                {
                if (FocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                        // Set the Focused object to green - success!
                        FocusedObject.GetComponent<Renderer>().material.color = Color.green;
    
                        // Start the Azure Function, to provide the next shape!
                        AzureServices.instance.CallAzureFunctionForNextShape();
                    }
                }
            }
        }
    
  4. Por último, adicione o método ResetFocusedObject() que irá alternar a cor atual dos objetos GazeButton, indicando se está a criar uma nova forma ou não.

        /// <summary>
        /// Reset the old focused object, stop the gaze timer, and send data if it
        /// is greater than one.
        /// </summary>
        private void ResetFocusedObject()
        {
            // Ensure the old focused object is not null.
            if (_oldFocusedObject != null)
            {
                if (_oldFocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                    // Set the old focused object to red - its original state.
                    _oldFocusedObject.GetComponent<Renderer>().material.color = Color.red;
                }
            }
        }
    
  5. Guarde as suas alterações na Visual Studio antes de regressar à Unidade.

  6. Clique e arraste a classe Gaze da pasta Scripts para o objeto da Câmara Principal no Painel hierarquia.

Capítulo 10 - Completar a classe AzureServices

Com os outros scripts em vigor, agora é possível completar a classe AzureServices. Isto será conseguido através de:

  1. Adicionar um novo método chamado CreateCloudIdentityAsync(), para configurar as variáveis de autenticação necessárias para comunicar com o Azure.

    Este método também verificará a existência de um Ficheiro previamente armazenado contendo a Lista de Formas.

    Se o ficheiro for encontrado,irá desativar o utilizador Gaze,e ativar a criação de Forma, de acordo com o padrão de formas, tal como armazenado no ficheiro Azure Armazenamento. O utilizador pode ver isto, uma vez que a Malha de Texto fornecerá o display 'Armazenamento' ou 'Novo', dependendo da origem das formas.

    Se não for encontrado nenhum ficheiro,ativará o Gaze,permitindo ao utilizador criar formas quando olha para o objeto GazeButton na cena.

        /// <summary>
        /// Create the references necessary to log into Azure
        /// </summary>
        private async void CreateCloudIdentityAsync()
        {
            // Retrieve storage account information from connection string
            storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    
            // Create a file client for interacting with the file service.
            fileClient = storageAccount.CreateCloudFileClient();
    
            // Create a share for organizing files and directories within the storage account.
            share = fileClient.GetShareReference(fileShare);
    
            await share.CreateIfNotExistsAsync();
    
            // Get a reference to the root directory of the share.
            CloudFileDirectory root = share.GetRootDirectoryReference();
    
            // Create a directory under the root directory
            dir = root.GetDirectoryReference(storageDirectory);
    
            await dir.CreateIfNotExistsAsync();
    
            //Check if the there is a stored text file containing the list
            shapeIndexCloudFile = dir.GetFileReference("TextShapeFile");
    
            if (!await shapeIndexCloudFile.ExistsAsync())
            {
                // File not found, enable gaze for shapes creation
                Gaze.instance.GazeEnabled = true;
    
                azureStatusText.text = "No Shape\nFile!";
            }
            else
            {
                // The file has been found, disable gaze and get the list from the file
                Gaze.instance.GazeEnabled = false;
    
                azureStatusText.text = "Shape File\nFound!";
    
                await ReplicateListFromAzureAsync();
            }
        }
    
  2. O próximo corte de código é do método Iniciar(). em que será feita uma chamada para o método CreateCloudIdentityAsync(). Sinta-se livre para copiar sobre o seu método iniciar () atual, com o seguinte:

        private void Start()
        {
            // Disable TLS cert checks only while in Unity Editor (until Unity adds support for TLS)
    #if UNITY_EDITOR
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    #endif
    
            // Set the Status text to loading, whilst attempting connection to Azure.
            azureStatusText.text = "Loading...";
    
            //Creating the references necessary to log into Azure and check if the Storage Directory is empty
            CreateCloudIdentityAsync();
        }
    
  3. Preencha o código para o método CallAzureFunctionForNextShape(). Utilizará a App de Função Azure anteriormente criada para solicitar um índice de forma. Uma vez que a nova forma é recebida, este método enviará a forma para a classe ShapeFactory para criar a nova forma na cena. Utilize o código abaixo para completar o corpo de CallAzureFunctionForNextShape().

        /// <summary>
        /// Call to the Azure Function App to request a Shape.
        /// </summary>
        public async void CallAzureFunctionForNextShape()
        {
            int azureRandomInt = 0;
    
            // Call Azure function
            HttpWebRequest webRequest = WebRequest.CreateHttp(azureFunctionEndpoint);
    
            WebResponse response = await webRequest.GetResponseAsync();
    
            // Read response as string
            using (Stream stream = response.GetResponseStream())
            {
                StreamReader reader = new StreamReader(stream);
    
                String responseString = reader.ReadToEnd();
    
                //parse result as integer
                Int32.TryParse(responseString, out azureRandomInt);
            }
    
            //add random int from Azure to the ShapeIndexList
            ShapeFactory.instance.shapeHistoryList.Add(azureRandomInt);
    
            ShapeFactory.instance.CreateShape(azureRandomInt, false);
    
            //Save to Azure storage
            await UploadListToAzureAsync();
        }
    
  4. Adicione um método para criar uma corda, concedendo os inteiros armazenados na lista de história de formas e guardando-o no seu Ficheiro Azure Armazenamento.

        /// <summary>
        /// Upload the locally stored List to Azure
        /// </summary>
        private async Task UploadListToAzureAsync()
        {
            // Uploading a local file to the directory created above
            string listToString = string.Join(",", ShapeFactory.instance.shapeHistoryList.ToArray());
    
            await shapeIndexCloudFile.UploadTextAsync(listToString);
        }
    
  5. Adicione um método para recuperar o texto armazenado no ficheiro localizado no seu Ficheiro Azure Armazenamento e deserializá-lo numa lista.

  6. Uma vez concluído este processo, o método volta a permitir o olhar para que o utilizador possa adicionar mais formas à cena.

        ///<summary>
        /// Get the List stored in Azure and use the data retrieved to replicate 
        /// a Shape creation pattern
        ///</summary>
        private async Task ReplicateListFromAzureAsync()
        {
            string azureTextFileContent = await shapeIndexCloudFile.DownloadTextAsync();
    
            string[] shapes = azureTextFileContent.Split(new char[] { ',' });
    
            foreach (string shape in shapes)
            {
                int i;
    
                Int32.TryParse(shape.ToString(), out i);
    
                ShapeFactory.instance.shapeHistoryList.Add(i);
    
                ShapeFactory.instance.CreateShape(i, true);
    
                await Task.Delay(500);
            }
    
            Gaze.instance.GazeEnabled = true;
    
            azureStatusText.text = "Load Complete!";
        }
    
  7. Guarde as suas alterações na Visual Studio antes de regressar à Unidade.

Capítulo 11 - Construir a Solução UWP

Para iniciar o processo de Construção:

  1. Vá para a Build deFicheiros Definições.

    construir a app

  2. Clique em Construir. A Unidade lançará uma janela do Explorador de Ficheiros, onde precisa de criar e, em seguida, selecionará uma pasta para construir a aplicação. Crie esta pasta agora, e nomeie-a App. Em seguida, com a pasta app selecionada, prima Select Folder.

  3. A unidade começará a construir o seu projeto para a pasta app.

  4. Uma vez terminada a construção da Unidade (pode demorar algum tempo), abrirá uma janela do Explorador de Ficheiros no local da sua construção (verifique a sua barra de tarefas, uma vez que pode nem sempre aparecer acima das suas janelas, mas irá notificá-lo da adição de uma nova janela).

Capítulo 12 - Implantação da sua aplicação

Para implementar a sua aplicação:

  1. Navegue para a pasta App criada no último Capítulo. Verá um ficheiro com o nome das suas aplicações, com a extensão '.sln', que deve clicar duas vezes, para o abrir dentro de Visual Studio.

  2. Na Plataforma solução,selecione x86, Máquina Local.

  3. Na Configuração da Solução selecione Debug.

    Para a Microsoft HoloLens, poderá ser mais fácil de configurar isto para Remote Machine, para que não esteja amarrado ao computador. No entanto, também terá de fazer o seguinte:

    • Conheça o Endereço IP do seu HoloLens, que pode ser encontrado dentro do DefiniçõesNetwork InternetWi-FiAdvanced Options; o IPv4 é o endereço que deve utilizar.
    • Certifique-se de que o modo de desenvolvimento está ligado; encontrado em DefiniçõesAtualizar Segurançapara desenvolvedores.

    implementar solução

  4. Vá ao menu Construir e clique na Solução De Implementação para carregar lateralmente a aplicação para a sua máquina.

  5. A sua App deve agora figurar na lista de aplicações instaladas, prontas a serem lançadas e testadas!

A sua aplicação de funções de Azure terminada e Armazenamento

Parabéns, você construiu uma aplicação de realidade mista que aproveita tanto as Funções Azure como os serviços de Armazenamento Azure. A sua aplicação poderá basear-se em dados armazenados e fornecer uma ação com base nesses dados.

produto final -fim

Exercícios de bónus

Exercício 1

Crie um segundo ponto de desova e registem qual ponto de desova de um objeto foi criado. Quando carregar o ficheiro de dados, reproduz as formas que estão a ser geradas a partir do local onde foram originalmente criadas.

Exercício 2

Crie uma forma de reiniciar a aplicação, em vez de ter de a reabrir sempre. As Cenas de Carregamento são um bom ponto de partida. Depois de o fazer, crie uma forma de limpar a lista armazenada no Azure Armazenamento– para que possa ser facilmente reposta a partir da sua aplicação.