Compartilhar via


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

Observação

Os tutoriais do Mixed Reality Academy foram projetados com o HoloLens (1ª geração) e os headsets imersivos de realidade misturada em mente. Dessa forma, achamos que é importante continuar disponibilizando esses tutoriais para os desenvolvedores que ainda buscam obter diretrizes para o desenvolvimento visando esses dispositivos. Esses tutoriais não serão atualizados com os conjuntos de ferramentas mais recentes nem com as interações usadas para o HoloLens 2. Eles serão mantidos para continuar funcionando nos dispositivos compatíveis. Haverá uma nova série de tutoriais que serão postados no futuro que demonstrarão como desenvolver para o HoloLens 2. Este aviso será atualizado com um link para esses tutoriais quando eles forem postados.

Neste curso, você aprenderá a usar o Microsoft Graph para fazer logon em sua conta da Microsoft usando a autenticação segura em um aplicativo de realidade misturada. 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ários conectados. Para obter mais informações, visite a página do Microsoft Graph.

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

Depois de concluir este curso, você terá um aplicativo HoloLens de realidade misturada, que poderá fazer o seguinte:

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

Em sua aplicação, cabe a você como integrará os resultados ao seu design. Este curso foi desenvolvido para ensinar como integrar um Serviço do Azure ao seu projeto do Unity. É seu trabalho usar o conhecimento adquirido com este curso para aprimorar seu aplicativo de realidade misturada.

Suporte a dispositivos

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

Pré-requisitos

Observação

Este tutorial foi desenvolvido para desenvolvedores que têm experiência básica com Unity e C#. Esteja ciente também de que os pré-requisitos e as instruções escritas 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 deste curso corresponderão perfeitamente ao que você encontrará em softwares mais recentes do que os listados abaixo.

Recomendamos o seguinte hardware e software para este curso:

Antes de começar

  1. Para evitar 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 no momento da compilação).
  2. Configure e teste 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 a calibração, siga este link para o artigo Calibração do HoloLens.

Para obter ajuda sobre o Ajuste do Sensor, siga este link para o artigo Ajuste do Sensor do HoloLens.

Capítulo 1 – Criar seu aplicativo no Portal de Registro de Aplicativos

Para começar, você precisará criar e registrar seu aplicativo no Portal de Registro de Aplicativos.

Neste capítulo, você também encontrará a chave de serviço que permitirá que você faça chamadas para o Microsoft Graph para acessar o conteúdo da sua conta.

  1. Navegue até o Portal de Registro de Aplicativos da Microsoft e faça logon com sua conta da Microsoft. Depois de fazer login, você será redirecionado para o Portal de Registro de Aplicativos.

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

    Captura de tela que mostra onde selecionar Adicionar um aplicativo.

    Importante

    O Portal de Registro de Aplicativos 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. Depois que o aplicativo for criado, você será redirecionado para a página principal do aplicativo. Copie a 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, certifique-se de que Aplicativo Nativo seja 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 tela que mostra a caixa de seleção Calendars.Read.

  8. Role até a parte inferior e clique no botão Salvar .

    Captura de tela que mostra onde selecionar Salvar.

  9. Seu salvamento será confirmado e você poderá sair do Portal de Registro de Aplicativos.

Capítulo 2 – Configurar o projeto do Unity

Veja a seguir uma configuração típica para desenvolvimento com realidade misturada e, como tal, é um bom modelo para outros projetos.

  1. Abra o Unity e clique em Novo.

    Captura de tela que mostra a interface do Unity.

  2. Você precisa fornecer um nome de projeto do Unity. Insira MSGraphMR. Certifique-se de que o modelo de projeto esteja definido como 3D. Defina o local para algum lugar apropriado para você (lembre-se, mais perto dos 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 Script Externo para Visual Studio 2017. Feche a janela Preferências.

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

  4. Vá para Configurações de Build de Arquivo>e selecione Plataforma Universal do Windows e clique no botão Alternar Plataforma para aplicar sua seleção.

    Captura de tela que mostra onde selecionar Alternar plataforma.

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

    1. O dispositivo de destino está definido como HoloLens

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

    3. O SDK está definido como Instalado mais recente

    4. A versão do Visual Studio está definida como Mais recente instalado

    5. Build and Run está definido como Computador Local

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

      1. Faça isso selecionando Adicionar cenas abertas. Uma janela de salvamento aparecerá.

        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 como 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

        Lembre-se de que você deve salvar suas cenas do Unity na pasta Ativos , pois elas devem estar associadas ao projeto do Unity. Criar a pasta scenes (e outras pastas semelhantes) é uma maneira típica de estruturar um projeto do Unity.

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

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

    Captura de tela que mostra a caixa de diálogo Configurações do Player.

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

    1. Na guia Outras configurações:

      1. A versão do tempo de execução de script deve ser experimental (equivalente ao .NET 4.6), o que disparará a necessidade de reiniciar o editor.

      2. O back-end de script 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, marque:

      • 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 com Suporte, verifique se o SDK do Windows Mixed Reality foi adicionado.

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

  8. De volta às Configurações de Build, os Projetos C# do Unity não estão mais esmaecidos; marque a caixa de seleção ao lado dela.

  9. Feche a janela Configurações de Build.

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

Capítulo 3 – Importar bibliotecas no Unity

Importante

Se você quiser ignorar o componente Configuração do Unity deste curso e continuar direto para o código, sinta-se à vontade para baixar este Azure-MR-311.unitypackage, importá-lo para seu projeto como um Pacote Personalizado e continuar do Capítulo 5.

Para usar o Microsoft Graph no 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 compilar o projeto do Unity (ou seja, editar o projeto após a compilação). É considerado mais simples importar as DLLs necessárias diretamente para o Unity.

Observação

Atualmente, há um problema conhecido no Unity que exige que os plug-ins sejam reconfigurados após a importação. Essas etapas (4 a 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ê quiser saber mais sobre como adicionar DLLs personalizadas ao seu projeto do Unity, siga este link.

Para importar o pacote:

  1. Adicione o Pacote do 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 do Unity que aparece, certifique-se de que tudo em (e incluindo) Plug-ins esteja 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, certifique-se de que Qualquer plataforma esteja desmarcada, verifique se o WSAPlayer também está desmarcado e clique em Aplicar. Isso é apenas para confirmar que os arquivos estão configurados corretamente.

    Captura de tela que mostra onde confirmar se Qualquer plataforma e WSAPlayer não estão marcados.

    Observação

    Marcar esses plug-ins os configura para serem usados apenas no Unity Editor. 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 Qualquer plataforma esteja desmarcada e que apenas o WSAPlayer esteja marcado.

    • Verifique se o SDK está definido como UWP e o Back-end de Script está definido como Dot Net

    • Certifique-se de que a opção Não processar esteja marcada.

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

  7. Clique em Aplicar.

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

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

  1. No Painel de Hierarquia, selecione a Câmera Principal.

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

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

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

    3. Certifique-se de que a Posição de transformação esteja definida como 0, 0, 0

    4. Definir sinalizadores claros para cor sólida

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

      Captura de tela que destaca onde definir a cor 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 de 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 essa 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 tela 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( ). Eles serão chamados quando a classe for inicializada:

        /// <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 por criar a interface do usuário do Meetings 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 essa 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 como 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ê observará que partes do código neste script são encapsuladas em torno de 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;
    
    

    Observação

    Altere o valor appId para ser a ID do aplicativo que você anotou no Capítulo 1, etapa 4. Esse valor deve ser o mesmo exibido no Portal de Registro de Aplicativos, na página de registro do aplicativo.

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

        /// <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 intervalo 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 do Graph . Salve suas alterações no Visual Studio antes de retornar ao Unity.

Capítulo 7 – Criar o script GazeInput

Agora você criará o GazeInput. Essa classe manipula e controla o olhar do usuário, usando um Raycast vindo da câmera principal, projetando 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 como GazeInput.

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

  4. Altere o código dos namespaces para corresponder ao abaixo, juntamente com a adição da marca '[System.Serializable]' acima da classe GazeInput , para que ela possa ser serializada:

    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 do 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 permitem que o Raycast de foco e acompanhe os 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:

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

  • Criando o objeto "botão" de logon 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 como Interações.

  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 responde ao evento do usuário Tap .

        /// <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 suas 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 Projeto, arraste o script Interações para o objeto Câmera principal, conforme ilustrado abaixo.

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

Capítulo 10 - Configurando a Tag

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

Para criar a marca:

  1. No Editor do Unity, clique na Câmera Principal no Painel de Hierarquia.

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

    Captura de tela que destaca a opção Adicionar Tag... 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 tela que mostra onde adicionar o nome da marca SignInButton.

Capítulo 11 – Criar o projeto do Unity para UWP

Tudo o que é necessário para a seção Unity deste projeto foi concluído, então é hora de construí-lo a partir do 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 Build.

  2. Se ainda não estiver, marque Projetos C# do Unity.

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

  4. O Unity começará a criar seu projeto na pasta App .

  5. Depois que o Unity terminar de compilar (pode levar algum tempo), ele abrirá uma janela do Explorador de Arquivos no local da compilação (verifique a barra de tarefas, pois nem sempre ela aparece acima das 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 HoloLens (para implantação remota) e garantir que o HoloLens esteja no modo de desenvolvedor. Para fazer isso:

    1. Enquanto estiver usando seu HoloLens, abra as Configurações.

    2. Ir para Rede e Internet>Wi-Fi>Opções avançadas

    3. Observe o endereço IPv4 .

    4. Em seguida, navegue de volta para Configurações e, em seguida, para Atualização e segurança>para desenvolvedores

    5. Ative o modo de desenvolvedor.

  2. Navegue até o novo build do 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ções, selecione x86, Computador Remoto. Você será solicitado a inserir o endereço IP de um dispositivo remoto (o HoloLens, neste caso, que você anotou).

    Captura de tela que mostra onde selecionar x86 e Remote Machine.

  5. Vá para o menu Compilar e clique em Implantar Solução para fazer sideload do aplicativo em seu HoloLens.

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

Seu aplicativo HoloLens do Microsoft Graph

Parabéns, você criou um aplicativo de realidade misturada 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 misturada 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 / número de telefone / foto de perfil do usuário

Exercício 1

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