HoloLens (första generationen) och Azure 311 – Microsoft Graph

Anteckning

Självstudierna Mixed Reality Academy har utformats med HoloLens (1:a gen) och Mixed Reality Immersive Headsets i åtanke. Därför anser vi att det är viktigt att lämna de här självstudierna på plats för utvecklare som fortfarande letar efter vägledning i utvecklingen för dessa enheter. De här självstudierna uppdateras inte med de senaste verktygen eller interaktionerna som används för HoloLens 2. De kommer att finnas kvar för att fortsätta arbeta med de enheter som stöds. Det kommer att finnas en ny serie självstudier som kommer att publiceras i framtiden som visar hur du utvecklar för HoloLens 2. Det här meddelandet uppdateras med en länk till dessa självstudier när de publiceras.

I den här kursen får du lära dig hur du använder Microsoft Graph för att logga in på din Microsoft-konto med säker autentisering i ett program med mixad verklighet. Sedan hämtar och visar du dina schemalagda möten i programgränssnittet.

Microsoft Graph är en uppsättning API:er som har utformats för att ge åtkomst till många av Microsofts tjänster. Microsoft beskriver Microsoft Graph som en matris med resurser som är anslutna via relationer, vilket innebär att ett program kan komma åt alla typer av anslutna användardata. Mer information finns på Microsofts Graph sida.

Utvecklingen omfattar att skapa en app där användaren uppmanas att titta på och sedan trycka på en sfär, vilket uppmanar användaren att logga in på ett säkert Microsoft-konto. När användaren har loggat in på sitt konto kan han eller hon se en lista över möten som schemalagts för dagen.

När du har slutfört den här kursen har du HoloLens ett program för mixad verklighet som kan göra följande:

  1. Med hjälp av gesten Tryck trycker du på ett objekt, vilket uppmanar användaren att logga in på ett Microsoft-konto (flytta ut ur appen för att logga in och sedan tillbaka till appen igen).
  2. Visa en lista över möten som är schemalagda för dagen.

I ditt program är det upp till dig hur du ska integrera resultaten med din design. Den här kursen är utformad för att lära dig hur du integrerar en Azure-tjänst med ditt Unity-projekt. Det är ditt jobb att använda den kunskap du får från den här kursen för att förbättra programmet för mixad verklighet.

Stöd för enheter

Kurs HoloLens Integrerande headset
MR och Azure 311: Microsoft Graph ✔️

Förutsättningar

Anteckning

Den här självstudien är utformad för utvecklare som har grundläggande erfarenhet av Unity och C#. Tänk också på att förutsättningarna och de skrivna anvisningarna i det här dokumentet representerar det som har testats och verifierats i skrivande stund (juli 2018). Du kan använda den senaste programvaran enligt listan i artikeln Installera verktyg, men det bör inte antas att informationen i den här kursen matchar det du hittar i nyare programvara än vad som anges nedan.

Vi rekommenderar följande maskin- och programvara för den här kursen:

Innan du börjar

  1. För att undvika problem med att skapa det här projektet rekommenderar vi starkt att du skapar projektet som nämns i den här självstudien i en rotmapp eller nära rotmappen (långa mappsökvägar kan orsaka problem vid byggtiden).
  2. Konfigurera och testa HoloLens. Om du behöver support för att konfigurera HoloLens kan du läsa artikeln om HoloLens konfiguration.
  3. Det är en bra idé att utföra kalibrering och sensorjustering när du börjar utveckla en ny HoloLens-app (ibland kan det hjälpa att utföra dessa uppgifter för varje användare).

Om du behöver hjälp med kalibrering följer du den här länken till artikeln HoloLens Kalibrering.

Om du behöver hjälp med sensorjustering följer du den här länken till artikeln om HoloLens sensorjustering.

Kapitel 1 – Skapa din app i programregistreringsportalen

Till att börja med måste du skapa och registrera ditt program i programregistreringsportalen.

I det här kapitlet hittar du även tjänstnyckeln som gör att du kan göra anrop till Microsoft Graph att komma åt ditt kontoinnehåll.

  1. Gå till Microsoft Application Registration Portal och logga in med ditt Microsoft-konto. När du har loggat in omdirigeras du till programregistreringsportalen.

  2. I avsnittet Mina program klickar du på knappen Lägg till en app.

    Viktigt

    Programregistreringsportalen kan se annorlunda ut beroende på om du tidigare har arbetat med Microsoft Graph. Skärmbilderna nedan visar dessa olika versioner.

  3. Lägg till ett namn för programmet och klicka på Skapa.

  4. När programmet har skapats omdirigeras du till programmets huvudsida. Kopiera program-ID:t och notera det här värdet på en säker plats. Du kommer snart att använda det i koden.

  5. I avsnittet Plattformar kontrollerar du att Inbyggt program visas. Om du inte klickar du på Lägg till plattform och väljer Ursprungligt program.

  6. Rulla nedåt på samma sida och i avsnittet Microsoft Graph behörigheter måste du lägga till ytterligare behörigheter för programmet. Klicka på Lägg till bredvid Delegerade behörigheter.

  7. Eftersom du vill att programmet ska få åtkomst till användarens kalender markerar du kryssrutan Calendars.Read och klickar på OK.

  8. Rulla längst ned och klicka på knappen Spara.

  9. Spara kommer att bekräftas och du kan logga ut från programregistreringsportalen.

Kapitel 2 – Konfigurera Unity-projektet

Följande är en typisk uppsättning för utveckling med mixad verklighet och är därför en bra mall för andra projekt.

  1. Öppna Unity och klicka på Ny.

  2. Du måste ange ett Unity-projektnamn. Infoga MSGraphMR. Kontrollera att projektmallen är inställd på 3D. Ställ in Plats på en lämplig plats (kom ihåg att närmare rotkataloger är bättre). Klicka sedan på Skapa projekt.

  3. När Unity är öppet är det värt att kontrollera att standardskriptredigeraren är inställd på Visual Studio. Gå till Redigera inställningar och gå sedan till Externa verktyg > från det nya fönstret. Ändra Extern skriptredigerare till Visual Studio 2017. Stäng fönstret Inställningar.

  4. Gå till File Build Inställningar (Filbygge) > och välj Universal Windows Platform (Universell Windows Platform) och klicka sedan på knappen Switch Platform (Växla plattform) för att tillämpa ditt val.

  5. När du fortfarande är > i Inställningar bör du se till att:

    1. Målenheten är inställd på HoloLens

    2. Byggtyp har angetts till D3D

    3. SDK är inställt på Senaste installerade

    4. Visual Studio Version har angetts till Senaste installerade

    5. Skapa och kör är inställt på Lokal dator

    6. Spara scenen och lägg till den i bygget.

      1. Gör detta genom att välja Lägg till öppna scener. Ett spara-fönster visas.

      2. Skapa en ny mapp för den här och framtida scenen. Välj knappen Ny mapp för att skapa en ny mapp och ge den namnet Scenes.

      3. Öppna den nyligen skapade mappen Scenes och skriv sedan i fältet Filnamn: text MR_ComputerVisionScene och klicka sedan på Spara.

        Viktigt

        Tänk på att du måste spara dina Unity-scener i mappen Tillgångar, eftersom de måste associeras med Unity-projektet. Att skapa mappen scenes (och andra liknande mappar) är ett vanligt sätt att strukturera ett Unity-projekt.

    7. De återstående inställningarna, i Build Inställningar, bör vara kvar som standard för tillfället.

  6. I fönstret Skapa Inställningar klickar du på knappen Player Inställningar(Spelare) så öppnas den relaterade panelen i utrymmet där Inspector finns.

  7. I den här panelen måste några inställningar verifieras:

    1. På fliken Inställningar:

      1. Skriptkörningsversion bör vara experimentell (.NET 4.6-motsvarighet), vilket utlöser ett behov av att starta om redigeraren.

      2. Skript backend ska vara .NET

      3. API-kompatibilitetsnivån ska vara .NET 4.6

    2. På fliken Inställningar, under Funktioner, markerar du:

      • InternetClient

    3. Längre ned i panelen, i XR Inställningar (finns nedan Publicera Inställningar), kontrollerar du Virtual Reality Supported (Virtuell verklighet stöds) och kontrollerar att Windows Mixed Reality SDK har lagts till.

  8. Tillbaka i Build Inställningar är Unity C#-projekt inte längre nedtonade; markera kryssrutan bredvid detta.

  9. Stäng fönstret Build Settings (Bygginställningar).

  10. Spara din scen och ditt projekt (FILE > SAVE SCENES/FILE > SAVE PROJECT).

Kapitel 3 – Importera bibliotek i Unity

Viktigt

Om du vill hoppa över komponenten Unity Set up i den här kursen och fortsätta direkt i koden kan du ladda ned azure-MR-311.unitypackage,importera den till ditt projekt som ett anpassat paket ochsedan fortsätta från kapitel 5.

Om du vill Graph Microsoft-program i Unity måste du använda DLL-filen Microsoft.Identity.Client. Det är möjligt att använda Microsoft Graph SDK, men det kräver att du lägger till ett NuGet-paket när du har byggt Unity-projektet (vilket innebär att du redigerar projektet efter bygget). Det anses vara enklare att importera nödvändiga DLL:er direkt till Unity.

Anteckning

Det finns för närvarande ett känt problem i Unity som kräver att plugin-program konfigureras om efter importen. De här stegen (4–7 i det här avsnittet) krävs inte längre efter att buggen har lösts.

Om du vill importera Microsoft Graph till ditt eget projekt laddar du MSGraph_LabPlugins.zip filen. Det här paketet har skapats med versioner av de bibliotek som har testats.

Om du vill veta mer om hur du lägger till anpassade DLL:er i Ditt Unity-projekt följer du den här länken.

Så här importerar du paketet:

  1. Lägg till Unity-paketet till Unity med hjälp av > menyalternativet Assets Import Package Custom > Package (Anpassat paket för tillgångars importpaket). Välj det paket som du precis laddade ned.

  2. I rutan Importera Unity-paket som visas ser du till att allt under (och inklusive) Plugin-program är markerat.

  3. Klicka på knappen Importera för att lägga till objekten i projektet.

  4. Gå till MSGraph-mappen under Plugin-program i Project panelen och välj plugin-programmet Microsoft.Identity.Client.

  5. När plugin-programmet är markerat kontrollerar du att Any Platform (Valfri plattform) är avmarkerat. Kontrollera sedan att WSA Player också är avmarkerat och klicka sedan på Apply (Använd). Detta är bara för att bekräfta att filerna är korrekt konfigurerade.

    Anteckning

    När du markerar dessa plugin-program konfigureras de så att de endast används i Unity-redigeraren. Det finns en annan uppsättning DLL:er i WSA-mappen som används när projektet har exporterats från Unity som ett Universal Windows-program.

  6. Därefter måste du öppna WSA-mappen i MSGraph-mappen. Du ser en kopia av samma fil som du just konfigurerade. Markera filen och sedan i kontrollen:

    • se till att Any Platform är avmarkerat och att endast WSAPlay är markerat.

    • Kontrollera att SDK är inställt på UWP och att Scripting Backend är inställt på Dot Net

    • Kontrollera att Bearbeta inte är markerat.

  7. Klicka på Applicera.

Kapitel 4 – Kamerainstallation

Under det här kapitlet ställer du in din scens huvudkamera:

  1. I hierarkipanelen väljer du huvudkameran.

  2. När du har valt det här alternativet kan du se alla komponenter i huvudkamerankontrollpanelen.

    1. Kameraobjektet måste ha namnet Huvudkamera (observera stavningen!)

    2. Huvudkamerataggen måste vara inställd på MainCamera (observera stavningen!)

    3. Kontrollera att transformeringspositionen är inställd på 0, 0, 0

    4. Ange Rensa flaggor till Solid Color

    5. Ange Bakgrundsfärg för kamerakomponenten till Svart, Alfa 0 (Hexkod: #00000000)

  3. Den slutliga objektstrukturen i hierarkipanelen bör se ut som på bilden nedan:

Kapitel 5 – Skapa mötenUI-klass

Det första skriptet du behöver skapa är MeetingsUI, som ansvarar för att vara värd för och fylla i programmets användargränssnitt (välkomstmeddelande, instruktioner och information om möten).

Så här skapar du den här klassen:

  1. Högerklicka på mappen Tillgångar i panelen Project och välj sedan Skapa > mapp. Ge mappen namnet Skript.

  2. Öppna mappen Skript och högerklicka sedan på Skapa C#-skript i > den mappen. Ge skriptet namnet MeetingsUI.

  3. Dubbelklicka på det nya MeetingsUI-skriptet för att öppna det med Visual Studio.

  4. Infoga följande namnområden:

    using System;
    using UnityEngine;
    
  5. Infoga följande variabler i klassen:

        /// <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. Ersätt sedan metoden Start() och lägg till en Awake()-metod. Dessa anropas när klassen initieras:

        /// <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. Lägg till de metoder som ansvarar för att skapa användargränssnittet för möten och fyll i det med de aktuella mötena när det begärs:

        /// <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. Ta bort metoden Update() och spara ändringarna i Visual Studio innan du återgår till Unity.

Kapitel 6 – Skapa Graph klass

Nästa skript som ska skapas är Graph skript. Det här skriptet ansvarar för att göra anropen för att autentisera användaren och hämta schemalagda möten för den aktuella dagen från användarens kalender.

Så här skapar du den här klassen:

  1. Dubbelklicka på mappen Skript för att öppna den.

  2. Högerklicka i mappen Skript och klicka på Skapa > C#-skript. Ge skriptet namnet Graph.

  3. Dubbelklicka på skriptet för att öppna det med Visual Studio.

  4. Infoga följande namnområden:

    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
    

    Viktigt

    Du kommer att märka att delar av koden i det här skriptet är omslutna runt förkompilerade direktiv.Det här är för att undvika problem med biblioteken när du skapar Visual Studio lösningen.

  5. Ta bort metoderna Start() och Update(), eftersom de inte kommer att användas.

  6. Utanför klassen Graph in följande objekt, som behövs för att deserialisera JSON-objektet som representerar de dagliga schemalagda mötena:

    /// <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. I Graph lägger du till följande variabler:

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

    Anteckning

    Ändra appId-värdet till det app-ID som du antecknade i kapitel 1, steg 4. Det här värdet ska vara samma som det som visas i programregistreringsportalen på programregistreringssidan.

  8. I klassen Graph lägger du till metoderna SignInAsync() och AquireTokenAsync() som uppmanar användaren att infoga inloggningsuppgifterna.

        /// <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. Lägg till följande två metoder:

    1. BuildTodayCalendarEndpoint(), som skapar den URI som anger dag och tidsintervall, där de schemalagda mötena hämtas.

    2. ListMeetingsAsync(), som begär schemalagda möten från 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. Nu har du slutfört Graph skriptet. Spara dina ändringar i Visual Studio innan du återgår till Unity.

Kapitel 7 – Skapa skriptet GazeInput

Nu ska du skapa BlickInput. Den här klassen hanterar och håller reda på användarens blick med hjälp av en Raycast som kommer från huvudkameran och projicerar framåt.

Så här skapar du skriptet:

  1. Dubbelklicka på mappen Skript för att öppna den.

  2. Högerklicka i mappen Skript och klicka på Skapa > C#-skript. Ge skriptet namnet GazeInput.

  3. Dubbelklicka på skriptet för att öppna det med Visual Studio.

  4. Ändra namnområdeskoden så att den matchar nedan, tillsammans med taggen [ System.Serializable ] ovanför klassen GazeInput så att den kan serialiseras:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. Lägg till följande variabler i klassen GazeInput:

        [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. Lägg till metoden CreateCursor() för att HoloLens markören i scenen och anropa metoden från metoden 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. Följande metoder aktiverar blicken Raycast och håller reda på de fokuserade objekten.

    /// <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. Spara dina ändringar i Visual Studio innan du återgår till Unity.

Kapitel 8 – Skapa klassen Interaktioner

Nu måste du skapa interaktionsskriptet, som ansvarar för:

  • Hantera interaktionen Tryck och Kamera blick, vilket gör att användaren kan interagera med inloggningsknappen i scenen.

  • Skapa "knapp"-objektet i scenen som användaren kan interagera med.

Så här skapar du skriptet:

  1. Dubbelklicka på mappen Skript för att öppna den.

  2. Högerklicka i mappen Skript och klicka på Skapa > C#-skript. Ge skriptet namnet Interactions.

  3. Dubbelklicka på skriptet för att öppna det med Visual Studio.

  4. Infoga följande namnområden:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Ändra arvet för klassen Interaction från MonoBehaviour till GazeInput.

    public class Interactions : MonoBehaviour

    public class Interactions : GazeInput
    
  6. Infoga följande variabel i klassen Interaction:

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Ersätt startmetoden; observera att det är en åsidosättningsmetod som anropar klassmetoden "base" Gaze. Start() anropas när klassen initierar, registrerar för igenkänning av indata och skapar inloggningsknappen i scenen:

        /// <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. Lägg till metoden CreateSignInButton(), som instansierar inloggningsknappen i scenen och anger dess egenskaper:

        /// <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. Lägg till GestureRecognizer_Tapped() som svarar för användarhändelsen Tryck.

        /// <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. Ta bort metoden Update() och spara sedan ändringarna i Visual Studio innan du återgår till Unity.

Kapitel 9 – Konfigurera skriptreferenserna

I det här kapitlet måste du placera interaktionsskriptethuvudkameran. Skriptet hanterar sedan att placera de andra skripten där de behöver vara.

  • Från mappen Skript i Project panelen drar du skriptet Interaktioner till huvudkameraobjektet, enligt bilden nedan.

Kapitel 10 – Konfigurera taggen

Koden som hanterar blicken använder Tag SignInButton för att identifiera vilket objekt användaren kommer att interagera med för att logga in på Microsoft Graph.

Så här skapar du taggen:

  1. I Unity-redigeraren klickar du på huvudkameranhierarkipanelen.

  2. I kontrollpanelen klickar du på taggen MainCamera för att öppna en listrutan. Klicka på Lägg till tagg...

  3. Klicka på + knappen .

  4. Skriv Tag name (Taggnamn) som SignInButton och klicka på Save (Spara).

Kapitel 11 – Skapa Unity-projektet till UWP

Allt som behövs för Unity-avsnittet i det här projektet har nu slutförts, så det är dags att bygga det från Unity.

  1. Gå till Build Inställningar (File > Build Inställningar).

  2. Om du inte redan gjort det markerar du Unity C # Projects.

  3. Klicka på Skapa. Unity startar ett Utforskaren där du behöver skapa och sedan välja en mapp att bygga appen i. Skapa mappen nu och ge den namnet App. När du har valt appmappen klickar du sedan på Välj mapp.

  4. Unity börjar skapa projektet i mappen App.

  5. När Unity har byggt klart (det kan ta lite tid) öppnas ett Utforskaren-fönster på platsen för bygget (markera aktivitetsfältet eftersom det kanske inte alltid visas ovanför dina fönster, men du får ett meddelande om att ett nytt fönster har öppnats).

Kapitel 12 – Distribuera till HoloLens

Så här distribuerar du på HoloLens:

  1. Du behöver IP-adressen för din HoloLens (för Fjärr distribuera) och för att se till att HoloLens är i utvecklarläge. Gör så här:

    1. När du använder HoloLens ska du öppna Inställningar.

    2. Gå till Nätverk & Avancerade alternativ för > Internet-Wi-Fi >

    3. Anteckna IPv4-adressen.

    4. Gå sedan tillbaka till Inställningar och sedan till Uppdatera & för > utvecklare

    5. Ställ in Utvecklarläge på.

  2. Navigera till din nya Unity-version (mappen App) och öppna lösningsfilen med Visual Studio.

  3. I Lösningskonfiguration väljer du Felsök.

  4. lösningsplattformen väljer du x86, Fjärrdator. Du uppmanas att infoga IP-adressen för en fjärransluten enhet (HoloLens, i det här fallet, som du antecknade).

  5. Gå till menyn Build (Skapa) och klicka på Deploy Solution (Distribuera lösning) för att separat ladda HoloLens.

  6. Din app bör nu visas i listan över installerade appar på HoloLens, redo att startas!

Ditt Microsoft Graph HoloLens program

Grattis! Du har skapat en app med mixad verklighet som använder Microsofts Graph för att läsa och visa användarens kalenderdata.

Bonusövningar

Övning 1

Använd Microsoft Graph att visa annan information om användaren

  • Bild av användarens e-post/telefonnummer/profil

Övning 1

Implementera röststyrning för att navigera i Microsofts Graph gränssnitt.