Partilhar via


HoloLens (1ª geração) e Azure 311 - Microsoft Graph

Nota

Os tutoriais da Academia de Realidade Mista foram projetados com HoloLens (1ª geração) e Headsets Imersivos de Realidade Mista em mente. Como tal, sentimos que é importante deixar estes tutoriais no lugar para desenvolvedores que ainda estão procurando orientação no desenvolvimento para esses dispositivos. Esses tutoriais não serão atualizados com os conjuntos de ferramentas ou interações mais recentes que estão sendo usados para o HoloLens 2. Eles serão mantidos para continuar trabalhando nos dispositivos suportados. Haverá uma nova série de tutoriais que serão publicados no futuro que demonstrarão como desenvolver para o HoloLens 2. Este aviso será atualizado com um link para esses tutoriais quando eles forem publicados.

Neste curso, você aprenderá a usar o Microsoft Graph para fazer logon em sua conta da Microsoft usando autenticação segura em um aplicativo de realidade mista. Em seguida, você recuperará e exibirá suas reuniões agendadas na interface do aplicativo.

Captura de tela que mostra as reuniões agendadas na interface do aplicativo.

O Microsoft Graph é um conjunto de APIs projetado para permitir o acesso a muitos dos serviços da Microsoft. A Microsoft descreve o Microsoft Graph como sendo uma matriz de recursos conectados por relações, o que significa que ele permite que um aplicativo acesse todos os tipos de dados de usuário conectados. Para obter mais informações, visite a página Microsoft Graph.

O desenvolvimento incluirá a criação de um aplicativo onde o usuário será instruído a olhar e, em seguida, tocar em uma esfera, o que solicitará que o usuário faça login com segurança em uma conta da Microsoft. Uma vez conectado à sua conta, o usuário poderá ver uma lista de reuniões agendadas para o dia.

Tendo concluído este curso, você terá um aplicativo HoloLens de realidade mista, que será capaz de fazer o seguinte:

  1. Usando o gesto Toque, toque em um objeto, que solicitará que o usuário faça login em uma Conta da Microsoft (saindo do aplicativo para fazer logon e entrando novamente no aplicativo novamente).
  2. Veja uma lista de reuniões agendadas para o dia.

Na sua aplicação, cabe-lhe a si decidir como irá integrar os resultados com o seu design. Este curso foi criado para ensiná-lo a integrar um Serviço do Azure ao seu projeto Unity. É seu trabalho usar o conhecimento que você ganha com este curso para melhorar sua aplicação de realidade mista.

Suporte de dispositivos

Curso HoloLens Auriculares imersivos
MR e Azure 311: Microsoft Graph ✔️

Pré-requisitos

Nota

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

Recomendamos o seguinte hardware e software para este curso:

Antes de começar

  1. Para evitar encontrar problemas ao criar este projeto, é altamente recomendável que você crie o projeto mencionado neste tutorial em uma pasta raiz ou quase raiz (caminhos de pasta longos podem causar problemas em tempo de compilação).
  2. Configure e teste o seu HoloLens. Se você precisar de suporte para configurar seu HoloLens, visite o artigo de configuração do HoloLens.
  3. É uma boa ideia executar a calibração e o ajuste do sensor ao começar a desenvolver um novo aplicativo HoloLens (às vezes, pode ajudar a executar essas tarefas para cada usuário).

Para obter ajuda sobre calibração, siga este link para o artigo Calibração HoloLens.

Para obter ajuda sobre o ajuste do sensor, siga este link para o artigo HoloLens Sensor Tuning.

Capítulo 1 - Crie seu aplicativo no Portal de Registro de Aplicativos

Para começar, terá de criar e registar a sua candidatura no Portal de Registo de Candidaturas.

Neste Capítulo, você também encontrará a Chave de Serviço que lhe permitirá fazer chamadas para o Microsoft Graph para acessar o conteúdo da sua conta.

  1. Navegue até ao Portal de Registo de Aplicações Microsoft e inicie sessão com a sua Conta Microsoft. Depois de iniciar sessão, será redirecionado para o Portal de Registo de Candidaturas.

  2. Na seção Meus aplicativos, clique no botão Adicionar um aplicativo.

    Captura de ecrã que mostra onde selecionar Adicionar uma aplicação.

    Importante

    O Portal de Registro de Aplicativo pode ter uma aparência diferente, dependendo se você já trabalhou com o Microsoft Graph. As capturas de tela abaixo exibem essas diferentes versões.

  3. Adicione um nome para seu aplicativo e clique em Criar.

    Captura de tela que mostra onde adicionar um nome para seu aplicativo.

  4. Uma vez que o aplicativo tenha sido criado, você será redirecionado para a página principal do aplicativo. Copie o ID do aplicativo e certifique-se de anotar esse valor em algum lugar seguro, você o usará em breve em seu código.

    Captura de tela que mostra onde exibir a ID do aplicativo.

  5. Na seção Plataformas, verifique se Aplicativo nativo é exibido. Caso contrário, clique em Adicionar plataforma e selecione Aplicativo nativo.

    Captura de tela que destaca a seção Aplicativo Nativo.

  6. Role para baixo na mesma página e na seção chamada Permissões do Microsoft Graph você precisará adicionar permissões adicionais para o aplicativo. Clique em Adicionar ao lado de Permissões delegadas.

    Captura de tela que mostra onde selecionar Adicionar ao lado de Permissões delegadas.

  7. Como você deseja que seu aplicativo acesse o Calendário do usuário, marque a caixa chamada Calendars.Read e clique em OK.

    Captura de ecrã que mostra a caixa de verificação Calendários.Ler.

  8. Desloque-se para a parte inferior e clique no botão Guardar .

    Captura de ecrã que mostra onde selecionar Guardar.

  9. A sua gravação será confirmada e poderá terminar sessão a partir do Portal de Registo de Candidaturas.

Capítulo 2 - Configurar o projeto Unity

O seguinte é uma configuração típica para desenvolver com realidade mista e, como tal, é um bom modelo para outros projetos.

  1. Abra o Unity e clique em Novo.

    Captura de tela que mostra a interface Unity.

  2. Você precisa fornecer um nome de projeto Unity. Insira MSGraphMR. Verifique se o modelo de projeto está definido como 3D. Defina o Local para algum lugar apropriado para você (lembre-se, mais perto de diretórios raiz é melhor). Em seguida, clique em Criar projeto.

    Captura de tela que mostra onde selecionar Criar projeto.

  3. Com o Unity aberto, vale a pena verificar se o Editor de Scripts padrão está definido como Visual Studio. Vá para Editar>Preferências e, na nova janela, navegue até Ferramentas Externas. Altere o Editor de Scripts Externo para Visual Studio 2017. Feche a janela Preferências .

    Captura de tela que mostra onde definir o Editor de Scripts Externo para o Visual Studio 2017.

  4. Vá para Configurações de compilação de arquivo>e selecione Plataforma Universal do Windows e, em seguida, clique no botão Alternar plataforma para aplicar sua seleção.

    Captura de tela que mostra onde selecionar Switch Platform.

  5. Enquanto ainda estiver em Configurações de compilação de arquivo>, certifique-se de que:

    1. O dispositivo alvo está definido como HoloLens

    2. O tipo de compilação está definido como D3D

    3. O SDK está definido como Instalado mais recente

    4. Versão do Visual Studio está definida como A versão mais recente instalada

    5. Build and Run está definido como Máquina Local

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

      1. Faça isso selecionando Adicionar cenas abertas. Será exibida uma janela de salvamento.

        Captura de tela que mostra onde selecionar Adicionar cenas abertas.

      2. Crie uma nova pasta para esta e qualquer cena futura. Selecione o botão Nova pasta , para criar uma nova pasta, nomeie-a Cenas.

        Captura de tela que mostra onde nomear a nova pasta.

      3. Abra a pasta Cenas recém-criada e, no campo de texto Nome do arquivo:, digite MR_ComputerVisionScene e clique em Salvar.

        Captura de tela que mostra onde digitar o nome do arquivo.

        Importante

        Esteja ciente, você deve salvar suas cenas Unity dentro da pasta Ativos , pois elas devem estar associadas ao projeto Unity. Criar a pasta scenes (e outras pastas semelhantes) é uma maneira típica de estruturar um projeto Unity.

    7. As configurações restantes, em Configurações de compilação, devem ser deixadas como padrão por enquanto.

  6. Na janela Configurações de compilação, clique no botão Configurações do player, isso abrirá o painel relacionado no espaço onde o inspetor está localizado.

    Captura de ecrã que mostra a caixa de diálogo Definições do Media Player.

  7. Neste painel, algumas configurações precisam ser verificadas:

    1. Na guia Outras configurações:

      1. A versão do Scripting Runtime deve ser experimental (equivalente ao .NET 4.6), o que acionará a necessidade de reiniciar o Editor.

      2. O back-end de scripts deve ser .NET

      3. O nível de compatibilidade da API deve ser .NET 4.6

        Captura de tela que mostra onde verificar o nível de compatibilidade da API.

    2. Na guia Configurações de publicação , em Recursos, verifique:

      • InternetClient

        Captura de tela que mostra onde selecionar a opção InternetClient.

    3. Mais abaixo no painel, em Configurações XR (encontradas abaixo de Configurações de publicação), marque Realidade Virtual suportada, verifique se o SDK de realidade mista do Windows foi adicionado.

      Captura de tela que mostra onde adicionar o Windows Mixed Reality SDK.

  8. De volta às Configurações de compilação, o Unity C# Projects não está mais acinzentado, marque a caixa de seleção ao lado disso.

  9. Feche a janela Configurações de compilação.

  10. Salve sua cena e projeto (FILE>SAVE SCENES / FILE>SAVE PROJECT).

Capítulo 3 - Importar bibliotecas em Unity

Importante

Se você deseja pular o componente Unity set deste curso e continuar direto no código, sinta-se à vontade para baixar este Azure-MR-311.unitypackage, importá-lo para seu projeto como um pacote personalizado e continuar a partir do Capítulo 5.

Para usar o Microsoft Graph dentro do Unity, você precisa usar a DLL Microsoft.Identity.Client . É possível usar o SDK do Microsoft Graph, no entanto, ele exigirá a adição de um pacote NuGet depois de criar o projeto Unity (o que significa editar o projeto pós-compilação). É considerado mais simples importar as DLLs necessárias diretamente para o Unity.

Nota

Atualmente, há um problema conhecido no Unity que exige que os plug-ins sejam reconfigurados após a importação. Essas etapas (4 - 7 nesta seção) não serão mais necessárias depois que o bug for resolvido.

Para importar o Microsoft Graph para seu próprio projeto, baixe o arquivo MSGraph_LabPlugins.zip. Este pacote foi criado com versões das bibliotecas que foram testadas.

Se você deseja saber mais sobre como adicionar DLLs personalizadas ao seu projeto Unity, siga este link.

Para importar o pacote:

  1. Adicione o pacote Unity ao Unity usando a opção de menu Pacote personalizado do pacote>de importação de ativos.> Selecione o pacote que você acabou de baixar.

  2. Na caixa Importar pacote Unity que aparece, verifique se tudo em (e incluindo) Plug-ins está selecionado.

    Captura de tela que mostra os parâmetros de configuração selecionados em Plugins.

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

  4. Vá para a pasta MSGraph em Plug-ins no Painel do Projeto e selecione o plug-in chamado Microsoft.Identity.Client.

    Captura de tela que mostra o plug-in Microsoft.Identity.Client.

  5. Com o plug-in selecionado, verifique se Any Platform está desmarcado, certifique-se de que o WSAPlayer também esteja desmarcado e clique em Aplicar. Isso é apenas para confirmar que os arquivos estão configurados corretamente.

    Captura de tela que mostra onde confirmar que Any Platform e WSAPlayer não estão marcados.

    Nota

    Marcar esses plug-ins os configura para serem usados apenas no Editor Unity. Há um conjunto diferente de DLLs na pasta WSA que será usado depois que o projeto for exportado do Unity como um aplicativo Universal do Windows.

  6. Em seguida, você precisa abrir a pasta WSA , dentro da pasta MSGraph . Você verá uma cópia do mesmo arquivo que acabou de configurar. Selecione o arquivo e, em seguida, no inspetor:

    • certifique-se de que Any Platform está desmarcada e que apenas o WSAPlayer está marcado.

    • Verifique se o SDK está definido como UWP e se o Scripting Backend está definido como Dot Net

    • Certifique-se de que Não processar está marcado.

      Captura de tela que mostra que Não processar está selecionado.

  7. Clique em Aplicar.

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

Durante este capítulo, você configurará a câmera principal da sua cena:

  1. No Painel Hierarquia, selecione a Câmara Principal.

  2. Uma vez selecionado, você será capaz de ver todos os componentes da câmera principal no painel Inspetor.

    1. O objeto Camera deve ser chamado Main Camera (observe a ortografia!)

    2. A tag da câmera principal deve ser definida como MainCamera (observe a ortografia!)

    3. Verifique se a Posição de transformação está definida como 0, 0, 0

    4. Definir sinalizadores transparentes como cor sólida

    5. Defina a cor de fundo do componente da câmera para preto, alfa 0 (código hexadecimal: #00000000)

      Captura de tela que destaca onde definir a cor do plano de fundo.

  3. A estrutura final do objeto no Painel de Hierarquia deve ser como a mostrada na imagem abaixo:

    Captura de tela que mostra a estrutura final do objeto no Painel Hierarquia.

Capítulo 5 - Criar classe MeetingsUI

O primeiro script que você precisa criar é o MeetingsUI, que é responsável por hospedar e preencher a interface do usuário do aplicativo (mensagem de boas-vindas, instruções e detalhes das reuniões).

Para criar esta classe:

  1. Clique com o botão direito do mouse na pasta Ativos no Painel do Projeto e selecione Criar>Pasta. Nomeie a pasta Scripts.

    Captura de ecrã que mostra onde encontrar a pasta Ativos.Captura de tela que mostra onde criar a pasta Scripts.

  2. Abra a pasta Scripts e, dentro dessa pasta, clique com o botão direito do mouse em Criar>Script C#. Nomeie o script MeetingsUI.

    Captura de tela que mostra onde criar a pasta MeetingsUI.

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

  4. Insira os seguintes namespaces:

    using System;
    using UnityEngine;
    
  5. Dentro da classe insira as seguintes variáveis:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static MeetingsUI Instance;
    
        /// <summary>
        /// The 3D text of the scene
        /// </summary>
        private TextMesh _meetingDisplayTextMesh;
    
  6. Em seguida, substitua o método Start() e adicione um método Awake( ). Estes serão chamados quando a classe inicializar:

        /// <summary>
        /// Called on initialization
        /// </summary>
        void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Called on initialization, after Awake
        /// </summary>
        void Start ()
        {
            // Creating the text mesh within the scene
            _meetingDisplayTextMesh = CreateMeetingsDisplay();
        }
    
  7. Adicione os métodos responsáveis pela criação da interface do usuário de reuniões e preencha-a com as reuniões atuais quando solicitado:

        /// <summary>
        /// Set the welcome message for the user
        /// </summary>
        internal void WelcomeUser(string userName)
        {
            if(!string.IsNullOrEmpty(userName))
            {
                _meetingDisplayTextMesh.text = $"Welcome {userName}";
            }
            else 
            {
                _meetingDisplayTextMesh.text = "Welcome";
            }
        }
    
        /// <summary>
        /// Set up the parameters for the UI text
        /// </summary>
        /// <returns>Returns the 3D text in the scene</returns>
        private TextMesh CreateMeetingsDisplay()
        {
            GameObject display = new GameObject();
            display.transform.localScale = new Vector3(0.03f, 0.03f, 0.03f);
            display.transform.position = new Vector3(-3.5f, 2f, 9f);
            TextMesh textMesh = display.AddComponent<TextMesh>();
            textMesh.anchor = TextAnchor.MiddleLeft;
            textMesh.alignment = TextAlignment.Left;
            textMesh.fontSize = 80;
            textMesh.text = "Welcome! \nPlease gaze at the button" +
                "\nand use the Tap Gesture to display your meetings";
    
            return textMesh;
        }
    
        /// <summary>
        /// Adds a new Meeting in the UI by chaining the existing UI text
        /// </summary>
        internal void AddMeeting(string subject, DateTime dateTime, string location)
        {
            string newText = $"\n{_meetingDisplayTextMesh.text}\n\n Meeting,\nSubject: {subject},\nToday at {dateTime},\nLocation: {location}";
    
            _meetingDisplayTextMesh.text = newText;
        }
    
  8. Exclua o método Update() e salve suas alterações no Visual Studio antes de retornar ao Unity.

Capítulo 6 - Criar a classe Graph

O próximo script a ser criado é o script Graph . Esse script é responsável por fazer as chamadas para autenticar o usuário e recuperar as reuniões agendadas para o dia atual do calendário do usuário.

Para criar esta classe:

  1. Clique duas vezes na pasta Scripts para abri-la.

  2. Clique com o botão direito do mouse dentro da pasta Scripts, clique em Criar>script C#. Nomeie o script Graph.

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

  4. Insira os seguintes namespaces:

    using System.Collections.Generic;
    using UnityEngine;
    using Microsoft.Identity.Client;
    using System;
    using System.Threading.Tasks;
    
    #if !UNITY_EDITOR && UNITY_WSA
    using System.Net.Http;
    using System.Net.Http.Headers;
    using Windows.Storage;
    #endif
    

    Importante

    Você notará que partes do código neste script são encapsuladas em diretivas de pré-compilação, isso é para evitar problemas com as bibliotecas ao criar a solução do Visual Studio.

  5. Exclua os métodos Start() e Update(), pois eles não serão usados.

  6. Fora da classe Graph , insira os seguintes objetos, que são necessários para desserializar o objeto JSON que representa as reuniões agendadas diariamente:

    /// <summary>
    /// The object hosting the scheduled meetings
    /// </summary>
    [Serializable]
    public class Rootobject
    {
        public List<Value> value;
    }
    
    [Serializable]
    public class Value
    {
        public string subject { get; set; }
        public StartTime start { get; set; }
        public Location location { get; set; }
    }
    
    [Serializable]
    public class StartTime
    {
        public string dateTime;
    
        private DateTime? _startDateTime;
        public DateTime StartDateTime
        {
            get
            {
                if (_startDateTime != null)
                    return _startDateTime.Value;
                DateTime dt;
                DateTime.TryParse(dateTime, out dt);
                _startDateTime = dt;
                return _startDateTime.Value;
            }
        }
    }
    
    [Serializable]
    public class Location
    {
        public string displayName { get; set; }
    }
    
  7. Dentro da classe Graph , adicione as seguintes variáveis:

        /// <summary>
        /// Insert your Application Id here
        /// </summary>
        private string _appId = "-- Insert your Application Id here --";
    
        /// <summary>
        /// Application scopes, determine Microsoft Graph accessibility level to user account
        /// </summary>
        private IEnumerable<string> _scopes = new List<string>() { "User.Read", "Calendars.Read" };
    
        /// <summary>
        /// Microsoft Graph API, user reference
        /// </summary>
        private PublicClientApplication _client;
    
        /// <summary>
        /// Microsoft Graph API, authentication
        /// </summary>
        private AuthenticationResult _authResult;
    
    

    Nota

    Altere o valor appId para ser o ID do aplicativo que você anotou no Capítulo 1, etapa 4. Este valor deve ser o mesmo que o apresentado no Portal de Registo de Candidaturas, na sua página de registo de candidaturas.

  8. Dentro da classe Graph , adicione os métodos SignInAsync() e AquireTokenAsync(), que solicitarão que o usuário insira as credenciais de logon.

        /// <summary>
        /// Begin the Sign In process using Microsoft Graph Library
        /// </summary>
        internal async void SignInAsync()
        {
    #if !UNITY_EDITOR && UNITY_WSA
            // Set up Grap user settings, determine if needs auth
            ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
            string userId = localSettings.Values["UserId"] as string;
            _client = new PublicClientApplication(_appId);
    
            // Attempt authentication
            _authResult = await AcquireTokenAsync(_client, _scopes, userId);
    
            // If authentication is successful, retrieve the meetings
            if (!string.IsNullOrEmpty(_authResult.AccessToken))
            {
                // Once Auth as been completed, find the meetings for the day
                await ListMeetingsAsync(_authResult.AccessToken);
            }
    #endif
        }
    
        /// <summary>
        /// Attempt to retrieve the Access Token by either retrieving
        /// previously stored credentials or by prompting user to Login
        /// </summary>
        private async Task<AuthenticationResult> AcquireTokenAsync(
            IPublicClientApplication app, IEnumerable<string> scopes, string userId)
        {
            IUser user = !string.IsNullOrEmpty(userId) ? app.GetUser(userId) : null;
            string userName = user != null ? user.Name : "null";
    
            // Once the User name is found, display it as a welcome message
            MeetingsUI.Instance.WelcomeUser(userName);
    
            // Attempt to Log In the user with a pre-stored token. Only happens
            // in case the user Logged In with this app on this device previously
            try
            {
                _authResult = await app.AcquireTokenSilentAsync(scopes, user);
            }
            catch (MsalUiRequiredException)
            {
                // Pre-stored token not found, prompt the user to log-in 
                try
                {
                    _authResult = await app.AcquireTokenAsync(scopes);
                }
                catch (MsalException msalex)
                {
                    Debug.Log($"Error Acquiring Token: {msalex.Message}");
                    return _authResult;
                }
            }
    
            MeetingsUI.Instance.WelcomeUser(_authResult.User.Name);
    
    #if !UNITY_EDITOR && UNITY_WSA
            ApplicationData.Current.LocalSettings.Values["UserId"] = 
            _authResult.User.Identifier;
    #endif
            return _authResult;
        }
    
  9. Adicione os dois métodos a seguir:

    1. BuildTodayCalendarEndpoint(), que cria o URI especificando o dia e o período de tempo em que as reuniões agendadas são recuperadas.

    2. ListMeetingsAsync(), que solicita as reuniões agendadas do Microsoft Graph.

        /// <summary>
        /// Build the endpoint to retrieve the meetings for the current day.
        /// </summary>
        /// <returns>Returns the Calendar Endpoint</returns>
        public string BuildTodayCalendarEndpoint()
        {
            DateTime startOfTheDay = DateTime.Today.AddDays(0);
            DateTime endOfTheDay = DateTime.Today.AddDays(1);
            DateTime startOfTheDayUTC = startOfTheDay.ToUniversalTime();
            DateTime endOfTheDayUTC = endOfTheDay.ToUniversalTime();
    
            string todayDate = startOfTheDayUTC.ToString("o");
            string tomorrowDate = endOfTheDayUTC.ToString("o");
            string todayCalendarEndpoint = string.Format(
                "https://graph.microsoft.com/v1.0/me/calendarview?startdatetime={0}&enddatetime={1}",
                todayDate,
                tomorrowDate);
    
            return todayCalendarEndpoint;
        }
    
        /// <summary>
        /// Request all the scheduled meetings for the current day.
        /// </summary>
        private async Task ListMeetingsAsync(string accessToken)
        {
    #if !UNITY_EDITOR && UNITY_WSA
            var http = new HttpClient();
    
            http.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Bearer", accessToken);
            var response = await http.GetAsync(BuildTodayCalendarEndpoint());
    
            var jsonResponse = await response.Content.ReadAsStringAsync();
    
            Rootobject rootObject = new Rootobject();
            try
            {
                // Parse the JSON response.
                rootObject = JsonUtility.FromJson<Rootobject>(jsonResponse);
    
                // Sort the meeting list by starting time.
                rootObject.value.Sort((x, y) => DateTime.Compare(x.start.StartDateTime, y.start.StartDateTime));
    
                // Populate the UI with the meetings.
                for (int i = 0; i < rootObject.value.Count; i++)
                {
                    MeetingsUI.Instance.AddMeeting(rootObject.value[i].subject,
                                                rootObject.value[i].start.StartDateTime.ToLocalTime(),
                                                rootObject.value[i].location.displayName);
                }
            }
            catch (Exception ex)
            {
                Debug.Log($"Error = {ex.Message}");
                return;
            }
    #endif
        }
    
  10. Agora você concluiu o script Graph. Salve suas alterações no Visual Studio antes de retornar ao Unity.

Capítulo 7 - Criar o script GazeInput

Agora você vai criar o GazeInput. Esta classe manipula e controla o olhar do usuário, usando um Raycast vindo da câmera principal, projetando-se para frente.

Para criar o script:

  1. Clique duas vezes na pasta Scripts para abri-la.

  2. Clique com o botão direito do mouse dentro da pasta Scripts, clique em Criar>script C#. Nomeie o script GazeInput.

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

  4. Altere o código de namespaces para corresponder ao abaixo, juntamente com a adição da tag '[System.Serializable]' acima de sua classe GazeInput , para que ele possa ser serializado:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. Dentro da classe GazeInput , adicione as seguintes variáveis:

        [Tooltip("Used to compare whether an object is to be interacted with.")]
        internal string InteractibleTag = "SignInButton";
    
        /// <summary>
        /// Length of the gaze
        /// </summary>
        internal float GazeMaxDistance = 300;
    
        /// <summary>
        /// Object currently gazed
        /// </summary>
        internal GameObject FocusedObject { get; private set; }
    
        internal GameObject oldFocusedObject { get; private set; }
    
        internal RaycastHit HitInfo { get; private set; }
    
        /// <summary>
        /// Cursor object visible in the scene
        /// </summary>
        internal GameObject Cursor { get; private set; }
    
        internal bool Hit { get; private set; }
    
        internal Vector3 Position { get; private set; }
    
        internal Vector3 Normal { get; private set; }
    
        private Vector3 _gazeOrigin;
    
        private Vector3 _gazeDirection;
    
  6. Adicione o método CreateCursor() para criar o cursor HoloLens na cena e chame o método do método Start( ):

        /// <summary>
        /// Start method used upon initialisation.
        /// </summary>
        internal virtual void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
        /// <summary>
        /// Method to create a cursor object.
        /// </summary>
        internal 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 = new Vector3(0.05f, 0.05f, 0.05f);
            Material mat = new Material(Shader.Find("Diffuse"));
            newCursor.GetComponent<MeshRenderer>().material = mat;
            mat.color = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
            newCursor.SetActive(true);
    
            return newCursor;
        }
    
  7. Os métodos a seguir habilitam o olhar Raycast e manter o controle dos objetos focados.

    /// <summary>
    /// Called every frame
    /// </summary>
    internal virtual void Update()
    {
        _gazeOrigin = Camera.main.transform.position;
    
        _gazeDirection = Camera.main.transform.forward;
    
        UpdateRaycast();
    }
    /// <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))
            {
                // Provide the 'Gaze Exited' event.
                oldFocusedObject.SendMessage("OnGazeExited", SendMessageOptions.DontRequireReceiver);
            }
        }
    }
    
        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            oldFocusedObject = FocusedObject;
            RaycastHit hitInfo;
    
            // Initialise Raycasting.
            Hit = Physics.Raycast(_gazeOrigin,
                _gazeDirection,
                out hitInfo,
                GazeMaxDistance);
                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. If so, reset the focused object.
            if (FocusedObject != oldFocusedObject)
            {
                ResetFocusedObject();
                if (FocusedObject != null)
                {
                    if (FocusedObject.CompareTag(InteractibleTag))
                    {
                        // Provide the 'Gaze Entered' event.
                        FocusedObject.SendMessage("OnGazeEntered", 
                            SendMessageOptions.DontRequireReceiver);
                    }
                }
            }
        }
    
  8. Salve suas alterações no Visual Studio antes de retornar ao Unity.

Capítulo 8 - Criar a classe Interactions

Agora você precisará criar o script Interações , que é responsável por:

  • Manipulação da interação Tap e do Camera Gaze, que permite ao usuário interagir com o "botão" de login na cena.

  • Criação do objeto de login "button" na cena para o usuário interagir.

Para criar o script:

  1. Clique duas vezes na pasta Scripts para abri-la.

  2. Clique com o botão direito do mouse dentro da pasta Scripts, clique em Criar>script C#. Nomeie o script Interactions.

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

  4. Insira os seguintes namespaces:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Altere a herança da classe Interaction de MonoBehaviour para GazeInput.

    Interações de classe pública : MonoBehaviour

    public class Interactions : GazeInput
    
  6. Dentro da classe Interaction insira a seguinte variável:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Substitua o método Start , observe que é um método de substituição, que chama o método de classe Gaze 'base'. Start() será chamado quando a classe for inicializada, registrando-se para reconhecimento de entrada e criando o botão de entrada na cena:

        /// <summary>
        /// Called on initialization, after Awake
        /// </summary>
        internal override void Start()
        {
            base.Start();
    
            // Register the application to recognize HoloLens user inputs
            _gestureRecognizer = new GestureRecognizer();
            _gestureRecognizer.SetRecognizableGestures(GestureSettings.Tap);
            _gestureRecognizer.Tapped += GestureRecognizer_Tapped;
            _gestureRecognizer.StartCapturingGestures();
    
            // Add the Graph script to this object
            gameObject.AddComponent<MeetingsUI>();
            CreateSignInButton();
        }
    
  8. Adicione o método CreateSignInButton(), que instanciará o botão de entrada na cena e definirá suas propriedades:

        /// <summary>
        /// Create the sign in button object in the scene
        /// and sets its properties
        /// </summary>
        void CreateSignInButton()
        {
            GameObject signInButton = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    
            Material mat = new Material(Shader.Find("Diffuse"));
            signInButton.GetComponent<Renderer>().material = mat;
            mat.color = Color.blue;
    
            signInButton.transform.position = new Vector3(3.5f, 2f, 9f);
            signInButton.tag = "SignInButton";
            signInButton.AddComponent<Graph>();
        }
    
  9. Adicione o método GestureRecognizer_Tapped(), que será respondido para o evento Tap user.

        /// <summary>
        /// Detects the User Tap Input
        /// </summary>
        private void GestureRecognizer_Tapped(TappedEventArgs obj)
        {
            if(base.FocusedObject != null)
            {
                Debug.Log($"TAP on {base.FocusedObject.name}");
                base.FocusedObject.SendMessage("SignInAsync", SendMessageOptions.RequireReceiver);
            }
        }
    
  10. Exclua o método Update() e salve as alterações no Visual Studio antes de retornar ao Unity.

Capítulo 9 - Configurar as referências de script

Neste capítulo, você precisa colocar o script de interações na câmera principal. Esse script tratará de colocar os outros scripts onde eles precisam estar.

  • Na pasta Scripts no Painel do projeto, arraste as interações do script para o objeto da câmera principal, conforme mostrado abaixo.

    Captura de tela que mostra para onde arrastar o script Interações.

Capítulo 10 - Configurando a tag

O código que manipula o olhar usará o Tag SignInButton para identificar com qual objeto o usuário interagirá para entrar no Microsoft Graph.

Para criar a tag:

  1. No Editor Unity, clique na câmera principal no painel Hierarquia.

  2. No Painel do Inspetor, clique na tag MainCamera para abrir uma lista suspensa. Clique em Adicionar tag...

    Captura de ecrã que realça a opção Adicionar etiqueta... opção.

  3. Clique no + botão.

    Captura de tela que mostra o botão +.

  4. Escreva o nome da marca como SignInButton e clique em Salvar.

    Captura de ecrã que mostra onde adicionar o nome da etiqueta SignInButton.

Capítulo 11 - Construir o projeto Unity para UWP

Tudo o que é necessário para a seção Unity deste projeto já foi concluído, então é hora de construí-lo a partir de Unity.

  1. Navegue até Configurações de compilação (Configurações de compilação de arquivo>).

    Captura de tela que mostra a caixa de diálogo Configurações de compilação.

  2. Se ainda não tiver, marque Unity C# Projects.

  3. Clique em Compilar. Unity irá iniciar uma janela do Explorador de Arquivos, onde você precisa criar e, em seguida, selecionar uma pasta para construir o aplicativo. Crie essa pasta agora e nomeie-a como App. Em seguida, com a pasta App selecionada, clique em Selecionar pasta.

  4. Unity começará a construir seu projeto para a pasta App .

  5. Assim que o Unity terminar de construir (pode levar algum tempo), ele abrirá uma janela do Explorador de Arquivos no local da sua compilação (verifique sua barra de tarefas, pois nem sempre ela aparecerá acima de suas janelas, mas notificará você sobre a adição de uma nova janela).

Capítulo 12 - Implantar no HoloLens

Para implantar no HoloLens:

  1. Você precisará do endereço IP do seu HoloLens (para implantação remota) e para garantir que seu HoloLens esteja no modo de desenvolvedor. Para fazer isso:

    1. Enquanto estiver a usar o HoloLens, abra as Definições.

    2. Ir para Rede & Opções Avançadas de Wi-Fi>da Internet>

    3. Observe o endereço IPv4 .

    4. Em seguida, navegue de volta para Configurações e, em seguida, para Atualizar & Segurança>para desenvolvedores

    5. Defina o modo de desenvolvedor ativado.

  2. Navegue até sua nova compilação Unity (a pasta App) e abra o arquivo de solução com o Visual Studio.

  3. Na Configuração da Solução, selecione Depurar.

  4. Na Plataforma de Solução, selecione x86, Máquina Remota. Você será solicitado a inserir o endereço IP de um dispositivo remoto (o HoloLens, neste caso, que você observou).

    Captura de tela que mostra onde selecionar x86 e Máquina Remota.

  5. Vá para o menu Build e clique em Deploy Solution para fazer sideload do aplicativo para o seu HoloLens.

  6. Seu aplicativo agora deve aparecer na lista de aplicativos instalados no seu HoloLens, pronto para ser iniciado!

Seu aplicativo Microsoft Graph HoloLens

Parabéns, você criou um aplicativo de realidade mista que aproveita o Microsoft Graph, para ler e exibir dados do calendário do usuário.

Captura de tela que mostra o aplicativo de realidade mista concluído.

Exercícios de bónus

Exercício 1

Usar o Microsoft Graph para exibir outras informações sobre o usuário

  • E-mail do usuário / número de telefone / foto do perfil

Exercício 1

Implemente o controle de voz para navegar na interface do usuário do Microsoft Graph.